diff --git a/.gitignore b/.gitignore index 937be24..90a120f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,5 @@ -.gradle .idea -build *.iml -bin .classpath .settings .project diff --git a/CONTRIBUTING.adoc b/CONTRIBUTING.adoc index b8606d8..b6178f4 100644 --- a/CONTRIBUTING.adoc +++ b/CONTRIBUTING.adoc @@ -1,6 +1,6 @@ -= Contributing to Spring Session += Contributing to Spring Session MongoDB -Spring Session is released under the Apache 2.0 license. If you would like to contribute +Spring Session MongoDB is released under the Apache 2.0 license. If you would like to contribute something, or simply want to hack on the code this document should help you get started. == Code of Conduct diff --git a/Jenkinsfile b/Jenkinsfile deleted file mode 100644 index 5cc4ff1..0000000 --- a/Jenkinsfile +++ /dev/null @@ -1,107 +0,0 @@ -def projectProperties = [ - [$class: 'BuildDiscarderProperty', - strategy: [$class: 'LogRotator', numToKeepStr: '5']], - pipelineTriggers([cron('@daily')]) -] -properties(projectProperties) - -def SUCCESS = hudson.model.Result.SUCCESS.toString() -currentBuild.result = SUCCESS - -try { - parallel check: { - stage('Check') { - node { - checkout scm - try { - sh "./gradlew clean check --refresh-dependencies --no-daemon" - } catch(Exception e) { - currentBuild.result = 'FAILED: check' - throw e - } finally { - junit '**/build/*-results/*.xml' - } - } - } - }, - sonar: { - stage('Sonar') { - node { - checkout scm - withCredentials([string(credentialsId: 'spring-sonar.login', variable: 'SONAR_LOGIN')]) { - try { - sh "./gradlew clean sonarqube -PexcludeProjects='**/samples/**' -Dsonar.host.url=$SPRING_SONAR_HOST_URL -Dsonar.login=$SONAR_LOGIN --refresh-dependencies --no-daemon" - } catch(Exception e) { - currentBuild.result = 'FAILED: sonar' - throw e - } - } - } - } - }, - springio: { - stage('Spring IO') { - node { - checkout scm - try { - sh "./gradlew clean springIoCheck -PexcludeProjects='**/samples/**' --refresh-dependencies --no-daemon --stacktrace" - } catch(Exception e) { - currentBuild.result = 'FAILED: springio' - throw e - } finally { - junit '**/build/spring-io*-results/*.xml' - } - } - } - } - - if(currentBuild.result == 'SUCCESS') { - parallel ossrh : { - stage('OSSRH Deploy') { - node { - checkout scm - withCredentials([file(credentialsId: 'spring-signing-secring.gpg', variable: 'SIGNING_KEYRING_FILE')]) { - withCredentials([string(credentialsId: 'spring-gpg-passphrase', variable: 'SIGNING_PASSWORD')]) { - withCredentials([usernamePassword(credentialsId: 'oss-token', passwordVariable: 'OSSRH_PASSWORD', usernameVariable: 'OSSRH_USERNAME')]) { - sh "./gradlew uploadArchives -PexcludeProjects='**/samples/**' -Psigning.secretKeyRingFile=$SIGNING_KEYRING_FILE -Psigning.keyId=$SPRING_SIGNING_KEYID -Psigning.password=$SIGNING_PASSWORD -PossrhUsername=$OSSRH_USERNAME -PossrhPassword=$OSSRH_PASSWORD --refresh-dependencies --no-daemon" - } - } - } - } - } - }, - docs: { - stage('Deploy Docs') { - node { - checkout scm - withCredentials([file(credentialsId: 'docs.spring.io-jenkins_private_ssh_key', variable: 'DEPLOY_SSH_KEY')]) { - sh "./gradlew deployDocs -PdeployDocsSshKeyPath=$DEPLOY_SSH_KEY -PdeployDocsSshUsername=$SPRING_DOCS_USERNAME --refresh-dependencies --no-daemon --stacktrace" - } - } - } - } - } -} finally { - def buildStatus = currentBuild.result - def buildNotSuccess = !SUCCESS.equals(buildStatus) - def lastBuildNotSuccess = !SUCCESS.equals(currentBuild.previousBuild?.result) - - if(buildNotSuccess || lastBuildNotSuccess) { - - stage('Notifiy') { - node { - final def RECIPIENTS = [[$class: 'DevelopersRecipientProvider'], [$class: 'RequesterRecipientProvider']] - - def subject = "${buildStatus}: Build ${env.JOB_NAME} ${env.BUILD_NUMBER} status is now ${buildStatus}" - def details = """The build status changed to ${buildStatus}. For details see ${env.BUILD_URL}""" - - emailext ( - subject: subject, - body: details, - recipientProviders: RECIPIENTS, - to: "$SPRING_SECURITY_TEAM_EMAILS" - ) - } - } - } -} diff --git a/README.adoc b/README.adoc index e338b06..313a4e2 100644 --- a/README.adoc +++ b/README.adoc @@ -1,11 +1,9 @@ -image:https://badges.gitter.im/spring-projects/spring-session.svg[link="https://gitter.im/spring-projects/spring-session?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge"] +image:https://travis-ci.org/spring-projects/spring-session-data-mongodb.svg?branch=master["Build Status", link="https://travis-ci.org/spring-projects/spring-session-data-mongodb"] -image:https://travis-ci.org/spring-projects/spring-session.svg?branch=master["Build Status", link="https://travis-ci.org/spring-projects/spring-session"] += Spring Session MongoDB +Greg Turnquist -= Spring Session -Rob Winch - -Spring Session aims to provide a common infrastructure for managing sessions. This provides many benefits including: +Spring Session MongoDB provides a solution for Spring Session in a MongoDB data store. * Accessing a session from any environment (i.e. web, messaging infrastructure, etc) * In a web environment @@ -19,7 +17,7 @@ By participating, you are expected to uphold this code. Please report unaccepta = Spring Session Project Site -You can find the documentation, issue management, support, samples, and guides for using Spring Session at http://projects.spring.io/spring-session/ +You can find the documentation, issue management, support, samples, and guides for using Spring Session MongoDB at http://projects.spring.io/spring-session-data-mongodb/ = License diff --git a/docs/spring-session-docs.gradle b/docs/spring-session-docs.gradle deleted file mode 100644 index 086f758..0000000 --- a/docs/spring-session-docs.gradle +++ /dev/null @@ -1,44 +0,0 @@ -apply plugin: 'io.spring.convention.docs' -apply plugin: 'io.spring.convention.spring-test' - -dependencies { - testCompile project(':spring-session') - testCompile project(':spring-session-data-mongo') - testCompile project(':spring-session-data-redis') - testCompile "org.springframework:spring-jdbc" - testCompile "org.springframework:spring-messaging" - testCompile "org.springframework:spring-webmvc" - testCompile "org.springframework:spring-websocket" - testCompile "org.springframework.security:spring-security-config" - testCompile "org.springframework.security:spring-security-web" - testCompile "org.springframework.security:spring-security-test" - testCompile "junit:junit" - testCompile "org.mockito:mockito-core" - testCompile "org.springframework:spring-test" - testCompile "org.assertj:assertj-core" - testCompile "com.hazelcast:hazelcast" - testCompile "io.lettuce:lettuce-core" - testCompile "javax.servlet:javax.servlet-api" -} - -def versions = dependencyManagement.managedVersions - -asciidoctor { - def ghTag = snapshotBuild ? 'master' : project.version - def ghUrl = "https://github.com/spring-projects/spring-session/tree/$ghTag" - attributes 'version-snapshot': snapshotBuild, - 'version-milestone': milestoneBuild, - 'version-release': releaseBuild, - 'gh-url': ghUrl, - 'gh-samples-url': "$ghUrl/samples/", - 'download-url' : "https://github.com/spring-projects/spring-session/archive/${ghTag}.zip", - 'spring-session-version' : version, - 'spring-version' : versions['org.springframework:spring-core'], - 'lettuce-version' : versions['io.lettuce:lettuce-core'], - 'hazelcast-version' : versions['com.hazelcast:hazelcast'], - 'docs-itest-dir' : rootProject.projectDir.path + '/docs/src/integration-test/java/', - 'docs-test-dir' : rootProject.projectDir.path + '/docs/src/test/java/', - 'docs-test-resources-dir' : rootProject.projectDir.path + '/docs/src/test/resources/', - 'samples-dir' : rootProject.projectDir.path + '/samples/', - 'session-main-resources-dir' : rootProject.projectDir.path + '/spring-session/src/main/resources/' -} diff --git a/docs/src/docs/asciidoc/guides/boot-findbyusername.adoc b/docs/src/docs/asciidoc/guides/boot-findbyusername.adoc deleted file mode 100644 index b233e5e..0000000 --- a/docs/src/docs/asciidoc/guides/boot-findbyusername.adoc +++ /dev/null @@ -1,139 +0,0 @@ -= Spring Session - find by username -Rob Winch -:toc: - -This guide describes how to use Spring Session to find sessions by username. - -NOTE: The completed guide can be found in the <>. - - -[[findbyusername-assumptions]] -== Assumptions - -The guide assumes you have already added Spring Session using the built in Redis configuration support to your application. -The guide also assumes you have already applied Spring Security to your application. -However, we the guide will be somewhat general purpose and can be applied to any technology with minimal changes we will discuss. - -[NOTE] -==== -If you need to learn how to add Spring Session to your project, please refer to the listing of link:../#samples[samples and guides] -==== - -== About the Sample - -Our sample is using this feature to invalidate the users session that might have been compromised. -Consider the following scenario: - -* User goes to library and authenticates to the application -* User goes home and realizes they forgot to log out -* User can log in and terminate the session from the library using clues like the location, created time, last accessed time, etc. - -Wouldn't it be nice if we could allow the user to invalidate the session at the library from any device they authenticate with? -This sample demonstrates how this is possible. - -[[findbyindexnamesessionrepository]] -== FindByIndexNameSessionRepository - -In order to look up a user by their username, you must first choose a `SessionRepository` that implements link:../#api-findbyindexnamesessionrepository[FindByIndexNameSessionRepository]. -Our sample application assumes that the Redis support is already setup, so we are ready to go. - -== Mapping the username - -`FindByIndexNameSessionRepository` can only find a session by the username, if the developer instructs Spring Session what user is associated with the `Session`. -This is done by ensuring that the session attribute with the name `FindByUsernameSessionRepository.PRINCIPAL_NAME_INDEX_NAME` is populated with the username. - -Generally, speaking this can be done with the following code immediately after the user authenticates: - -[source,java,indent=0] ----- -include::{docs-test-dir}docs/FindByIndexNameSessionRepositoryTests.java[tags=set-username] ----- - -== Mapping the username with Spring Security - -Since we are using Spring Security, the user name is automatically indexed for us. -This means we will not have to perform any steps to ensure the user name is indexed. - -== Adding Additional Data to Session - -It may be nice to associate additional information (i.e. IP Address, the browser, location, etc) to the session. -This makes it easier for the user to know which session they are looking at. - -To do this simply determine which session attribute you want to use and what information you wish to provide. -Then create a Java bean that is added as a session attribute. -For example, our sample application includes the location and access type of the session - -[source,java,indent=0] ----- -include::{samples-dir}boot/findbyusername/src/main/java/sample/session/SessionDetails.java[tags=class] ----- - -We then inject that information into the session on each HTTP request using a `SessionDetailsFilter`. -For example: - -[source,java,indent=0] ----- -include::{samples-dir}boot/findbyusername/src/main/java/sample/session/SessionDetailsFilter.java[tags=dofilterinternal] ----- - -We obtain the information we want and then set the `SessionDetails` as an attribute in the `Session`. -When we retrieve the `Session` by username, we can then use the session to access our `SessionDetails` just like any other session attribute. - -[NOTE] -==== -You might be wondering at this point why Spring Session does not provide `SessionDetails` functionality out of the box. -The reason, is twofold. -The first is that it is very trivial for applications to implement this themselves. -The second reason is that the information that is populated in the session (and how frequently that information is updated) is highly application dependent. -==== - -== Finding sessions for a specific user - -We can now find all the sessions for a specific user. - -[source,java,indent=0] ----- -include::{samples-dir}boot/findbyusername/src/main/java/sample/mvc/IndexController.java[tags=findbyusername] ----- - -In our instance, we find all sessions for the currently logged in user. -However, this could easily be modified for an administrator to use a form to specify which user to look up. - -[[findbyusername-sample]] -== findbyusername Sample Application - -=== Running the findbyusername 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 `JedisConnectionFactory` to point to a Redis server. -==== - ----- -$ ./gradlew :samples:findbyusername:tomcatRun ----- - -You should now be able to access the application at http://localhost:8080/ - -=== Exploring the security Sample Application - -Try using the application. Enter the following to log in: - -* **Username** _user_ -* **Password** _password_ - -Now click the **Login** button. -You should now see a message indicating your are logged in with the user entered previously. -You should also see a listing of active sessions for the currently logged in user. - -Let's emulate the flow we discussed in the <> section - -* Open a new incognito window and navigate to http://localhost:8080/ -* Enter the following to log in: -** **Username** _user_ -** **Password** _password_ -* Terminate your original session -* Refresh the original window and see you are logged out diff --git a/docs/src/docs/asciidoc/guides/boot-jdbc.adoc b/docs/src/docs/asciidoc/guides/boot-jdbc.adoc deleted file mode 100644 index 2755f14..0000000 --- a/docs/src/docs/asciidoc/guides/boot-jdbc.adoc +++ /dev/null @@ -1,152 +0,0 @@ -= Spring Session - Spring Boot -Rob Winch, Vedran Pavić -:toc: - -This guide describes how to use Spring Session to transparently leverage a relational database to back a web application's `HttpSession` when using Spring Boot. - -NOTE: The completed guide can be found in the <>. - -== Updating Dependencies -Before you use Spring Session, you must ensure to update your dependencies. -We assume you are working with a working Spring Boot web application. -If you are using Maven, ensure to add the following dependencies: - -.pom.xml -[source,xml] -[subs="verbatim,attributes"] ----- - - - - - org.springframework.session - spring-session-jdbc - {spring-session-version} - - - org.springframework.boot - spring-boot-starter-jdbc - - ----- - -ifeval::["{version-snapshot}" == "true"] -Since we are using a SNAPSHOT version, we need to ensure to add the Spring Snapshot Maven Repository. -Ensure you have the following in your pom.xml: - -.pom.xml -[source,xml] ----- - - - - - - spring-snapshot - https://repo.spring.io/libs-snapshot - - ----- -endif::[] - -ifeval::["{version-milestone}" == "true"] -Since We are using a Milestone version, we need to ensure to add the Spring Milestone Maven Repository. -Ensure you have the following in your pom.xml: - -.pom.xml -[source,xml] ----- - - spring-milestone - https://repo.spring.io/libs-milestone - ----- -endif::[] - -// tag::config[] - -[[httpsession-jdbc-boot-spring-configuration]] -== Spring Configuration - -After adding the required dependencies, we can create our Spring configuration. -The Spring configuration is responsible for creating a Servlet Filter that replaces the `HttpSession` implementation with an implementation backed by Spring Session. -Add the following Spring Configuration: - -[source,java] ----- -include::{samples-dir}boot/jdbc/src/main/java/sample/config/HttpSessionConfig.java[tags=class] ----- - -<1> The `@EnableJdbcHttpSession` annotation creates a Spring Bean with the name of `springSessionRepositoryFilter` that implements Filter. -The filter is what is in charge of replacing the `HttpSession` implementation to be backed by Spring Session. -In this instance Spring Session is backed by a relational database. - -[[httpsession-jdbc-boot-configuration]] -== Configuring the DataSource - -Spring Boot automatically creates a `DataSource` that connects Spring Session to an embedded instance of H2 database. -In a production environment you need to ensure to update your configuration to point to your relational database. -For example, you can include the following in your *application.properties* - -.src/main/resources/application.properties ----- -spring.datasource.url=jdbc:postgresql://localhost:5432/myapp -spring.datasource.username=myapp -spring.datasource.password=secret ----- - -For more information, refer to http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-configure-datasource[Configure a DataSource] portion of the Spring Boot documentation. - -[[httpsession-jdbc-boot-servlet-configuration]] -== Servlet Container Initialization - -Our <> created a Spring Bean named `springSessionRepositoryFilter` that implements `Filter`. -The `springSessionRepositoryFilter` bean is responsible for replacing the `HttpSession` with a custom implementation that is backed by Spring Session. - -In order for our `Filter` to do its magic, Spring needs to load our `Config` class. -Last we need to ensure that our Servlet Container (i.e. Tomcat) uses our `springSessionRepositoryFilter` for every request. -Fortunately, Spring Boot takes care of both of these steps for us. - -// end::config[] - -[[httpsession-jdbc-boot-sample]] -== httpsession-jdbc-boot Sample Application - -The httpsession-jdbc-boot Sample Application demonstrates how to use Spring Session to transparently leverage H2 database to back a web application's `HttpSession` when using Spring Boot. - -[[httpsession-jdbc-boot-running]] -=== Running the httpsession-jdbc-boot Sample Application - -You can run the sample by obtaining the {download-url}[source code] and invoking the following command: - ----- -$ ./gradlew :samples:httpsession-jdbc-boot:bootRun ----- - -You should now be able to access the application at http://localhost:8080/ - -[[httpsession-jdbc-boot-explore]] -=== Exploring the security Sample Application - -Try using the application. Enter the following to log in: - -* **Username** _user_ -* **Password** _password_ - -Now click the **Login** button. -You should now see a message indicating your are logged in with the user entered previously. -The user's information is stored in H2 database rather than Tomcat's `HttpSession` implementation. - -[[httpsession-jdbc-boot-how]] -=== How does it work? - -Instead of using Tomcat's `HttpSession`, we are actually persisting the values in H2 database. -Spring Session replaces the `HttpSession` with an implementation that is backed by a relational database. -When Spring Security's `SecurityContextPersistenceFilter` saves the `SecurityContext` to the `HttpSession` it is then persisted into H2 database. - -When a new `HttpSession` is created, Spring Session creates a cookie named SESSION in your browser that contains the id of your session. -Go ahead and view the cookies (click for help with https://developer.chrome.com/devtools/docs/resources#cookies[Chrome] or https://getfirebug.com/wiki/index.php/Cookies_Panel#Cookies_List[Firefox]). - -If you like, you can easily remove the session using H2 web console available at: http://localhost:8080/h2-console/ (use `jdbc:h2:mem:testdb` for JDBC URL) - -Now visit the application at http://localhost:8080/ and observe that we are no longer authenticated. diff --git a/docs/src/docs/asciidoc/guides/boot-redis.adoc b/docs/src/docs/asciidoc/guides/boot-redis.adoc deleted file mode 100644 index a80c004..0000000 --- a/docs/src/docs/asciidoc/guides/boot-redis.adoc +++ /dev/null @@ -1,162 +0,0 @@ -= Spring Session - Spring Boot -Rob Winch -:toc: - -This guide describes how to use Spring Session to transparently leverage Redis to back a web application's `HttpSession` when using Spring Boot. - -NOTE: The completed guide can be found in the <>. - -== Updating Dependencies -Before you use Spring Session, you must ensure to update your dependencies. -We assume you are working with a working Spring Boot web application. -If you are using Maven, ensure to add the following dependencies: - -.pom.xml -[source,xml] -[subs="verbatim,attributes"] ----- - - - - - org.springframework.session - spring-session - {spring-session-version} - - - org.springframework.boot - spring-boot-starter-data-redis - - ----- - -ifeval::["{version-snapshot}" == "true"] -Since We are using a SNAPSHOT version, we need to ensure to add the Spring Snapshot Maven Repository. -Ensure you have the following in your pom.xml: - -.pom.xml -[source,xml] ----- - - - - - - spring-snapshot - https://repo.spring.io/libs-snapshot - - ----- -endif::[] - -ifeval::["{version-milestone}" == "true"] -Since We are using a Milestone version, we need to ensure to add the Spring Milestone Maven Repository. -Ensure you have the following in your pom.xml: - -.pom.xml -[source,xml] ----- - - spring-milestone - https://repo.spring.io/libs-milestone - ----- -endif::[] - -[[boot-spring-configuration]] -== Spring Configuration - -After adding the required dependencies, we can create our Spring configuration. -The Spring configuration is responsible for creating a Servlet Filter that replaces the `HttpSession` implementation with an implementation backed by Spring Session. -Add the following Spring Configuration: - -[source,java] ----- -include::{samples-dir}boot/redis/src/main/java/sample/config/HttpSessionConfig.java[tags=class] ----- - -<1> The `@EnableRedisHttpSession` annotation creates a Spring Bean with the name of `springSessionRepositoryFilter` that implements Filter. -The filter is what is in charge of replacing the `HttpSession` implementation to be backed by Spring Session. -In this instance Spring Session is backed by Redis. - -[[boot-redis-configuration]] -== Configuring the Redis Connection - -Spring Boot automatically creates a `RedisConnectionFactory` that connects Spring Session to a Redis Server on localhost on port 6379 (default port). -In a production environment you need to ensure to update your configuration to point to your Redis server. -For example, you can include the following in your *application.properties* - -.src/main/resources/application.properties ----- -spring.redis.host=localhost -spring.redis.password=secret -spring.redis.port=6379 ----- - -For more information, refer to http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-connecting-to-redis[Connecting to Redis] portion of the Spring Boot documentation. - -[[boot-servlet-configuration]] -== Servlet Container Initialization - -Our <> created a Spring Bean named `springSessionRepositoryFilter` that implements `Filter`. -The `springSessionRepositoryFilter` bean is responsible for replacing the `HttpSession` with a custom implementation that is backed by Spring Session. - -In order for our `Filter` to do its magic, Spring needs to load our `Config` class. -Last we need to ensure that our Servlet Container (i.e. Tomcat) uses our `springSessionRepositoryFilter` for every request. -Fortunately, Spring Boot takes care of both of these steps for us. - -[[boot-sample]] -== boot Sample Application - -The boot Sample Application demonstrates how to use Spring Session to transparently leverage Redis to back a web application's `HttpSession` when using Spring Boot. - -[[boot-running]] -=== Running the boot 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 `JedisConnectionFactory` to point to a Redis server. -==== - ----- -$ ./gradlew :samples:boot:bootRun ----- - -You should now be able to access the application at http://localhost:8080/ - -[[boot-explore]] -=== Exploring the security Sample Application - -Try using the application. Enter the following to log in: - -* **Username** _user_ -* **Password** _password_ - -Now click the **Login** button. -You should now see a message indicating your are logged in with the user entered previously. -The user's information is stored in Redis rather than Tomcat's `HttpSession` implementation. - -[[boot-how]] -=== How does it work? - -Instead of using Tomcat's `HttpSession`, we are actually persisting the values in Redis. -Spring Session replaces the `HttpSession` with an implementation that is backed by Redis. -When Spring Security's `SecurityContextPersistenceFilter` saves the `SecurityContext` to the `HttpSession` it is then persisted into Redis. - -When a new `HttpSession` is created, Spring Session creates a cookie named SESSION in your browser that contains the id of your session. -Go ahead and view the cookies (click for help with https://developer.chrome.com/devtools/docs/resources#cookies[Chrome] or https://getfirebug.com/wiki/index.php/Cookies_Panel#Cookies_List[Firefox]). - -If you like, you can easily remove the session using redis-cli. For example, on a Linux based system you can type: - - $ redis-cli keys '*' | xargs redis-cli del - -TIP: The Redis documentation has instructions for http://redis.io/topics/quickstart[installing redis-cli]. - -Alternatively, you can also delete the explicit key. Enter the following into your terminal ensuring to replace `7e8383a4-082c-4ffe-a4bc-c40fd3363c5e` with the value of your SESSION cookie: - - $ redis-cli del spring:session:sessions:7e8383a4-082c-4ffe-a4bc-c40fd3363c5e - -Now visit the application at http://localhost:8080/ and observe that we are no longer authenticated. diff --git a/docs/src/docs/asciidoc/guides/boot-websocket.adoc b/docs/src/docs/asciidoc/guides/boot-websocket.adoc deleted file mode 100644 index cef009c..0000000 --- a/docs/src/docs/asciidoc/guides/boot-websocket.adoc +++ /dev/null @@ -1,138 +0,0 @@ -= Spring Session - WebSocket -Rob Winch -:toc: -:websocketdoc-test-dir: {docs-test-dir}docs/websocket/ - -This guide describes how to use Spring Session to ensure that WebSocket messages keep your HttpSession alive. - -// tag::disclaimer[] - -NOTE: Spring Session's WebSocket support only works with Spring's WebSocket support. -Specifically it does not work with using https://www.jcp.org/en/jsr/detail?id=356[JSR-356] directly. -This is due to the fact that JSR-356 does not have a mechanism for intercepting incoming WebSocket messages. - -// end::disclaimer[] - -== HttpSession Setup - -The first step is to integrate Spring Session with the HttpSession. These steps are already outlined in the link:httpsession.html[HttpSession Guide]. - -Please make sure you have already integrated Spring Session with the HttpSession before proceeding. - -// tag::config[] - -[[websocket-spring-configuration]] -== Spring Configuration - -In a typical Spring WebSocket application users would extend `AbstractWebSocketMessageBrokerConfigurer`. -For example, the configuration might look something like the following: - -[source,java] ----- -include::{websocketdoc-test-dir}WebSocketConfig.java[tags=class] ----- - -We can easily update our configuration to use Spring Session's WebSocket support. -For example: - -.src/main/java/samples/config/WebSocketConfig.java -[source,java] ----- -include::{samples-dir}boot/websocket/src/main/java/sample/config/WebSocketConfig.java[tags=class] ----- - -To hook in the Spring Session support we only need to change two things: - -<1> Instead of extending `AbstractWebSocketMessageBrokerConfigurer` we extend `AbstractSessionWebSocketMessageBrokerConfigurer` -<2> We rename the `registerStompEndpoints` method to `configureStompEndpoints` - -What does `AbstractSessionWebSocketMessageBrokerConfigurer` do behind the scenes? - -* `WebSocketConnectHandlerDecoratorFactory` is added as a `WebSocketHandlerDecoratorFactory` to `WebSocketTransportRegistration`. -This ensures a custom `SessionConnectEvent` is fired that contains the `WebSocketSession`. -The `WebSocketSession` is necessary to terminate any WebSocket connections that are still open when a Spring Session is terminated. -* `SessionRepositoryMessageInterceptor` is added as a `HandshakeInterceptor` to every `StompWebSocketEndpointRegistration`. -This ensures that the Session is added to the WebSocket properties to enable updating the last accessed time. -* `SessionRepositoryMessageInterceptor` is added as a `ChannelInterceptor` to our inbound `ChannelRegistration`. -This ensures that every time an inbound message is received, that the last accessed time of our Spring Session is updated. -* `WebSocketRegistryListener` is created as a Spring Bean. -This ensures that we have a mapping of all of the Session id to the corresponding WebSocket connections. -By maintaining this mapping, we can close all the WebSocket connections when a Spring Session (HttpSession) is terminated. - - -// end::config[] - -[[websocket-sample]] -== websocket Sample Application - -The websocket sample application demonstrates how to use Spring Session with WebSockets. - -=== Running the websocket Sample Application - -You can run the sample by obtaining the {download-url}[source code] and invoking the following command: - -[TIP] -==== -For the purposes of testing session expiration, you may want to change the session expiration to be 1 minute (default is 30 minutes) by removing the comment from the following file before starting the application: - -.src/main/java/samples/config/WebSecurityConfig.java -[source,java] ----- -include::{samples-dir}boot/websocket/src/main/java/sample/config/WebSecurityConfig.java[tags=enable-redis-httpsession] ----- -==== - -[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 `LettuceConnectionFactory` to point to a Redis server. -==== - ----- -$ ./gradlew :samples:websocket:bootRun ----- - -You should now be able to access the application at http://localhost:8080/ - -=== Exploring the websocket Sample Application - -Try using the application. Authenticate with the following information: - -* **Username** _rob_ -* **Password** _password_ - -Now click the **Login** button. You should now be authenticated as the user **rob**. - -Open an incognito window and access http://localhost:8080/ - -You will be prompted with a log in form. Authenticate with the following information: - -* **Username** _luke_ -* **Password** _password_ - -Now send a message from *rob* to *luke*. The message should appear. - -Wait for two minutes and try sending a message from *rob* to *luke* again. -You will see that the message is no longer sent. - -[NOTE] -.Why two minutes? -==== -Spring Session will expire in 60 seconds, but the notification from Redis is not guaranteed to happen within 60 seconds. -To ensure the socket is closed in a reasonable amount of time, Spring Session runs a background task every minute at 00 seconds that forcibly cleans up any expired sessions. -This means you will need to wait at most two minutes before the WebSocket connection is terminated. -==== - -Try accessing http://localhost:8080/ -You will be prompted to authenticate again. -This demonstrates that the session properly expires. - -Now repeat the same exercise, but instead of waiting two minutes send a message from *each* of the users every 30 seconds. -You will see that the messages continue to be sent. -Try accessing http://localhost:8080/ -You will not be prompted to authenticate again. -This demonstrates the session is kept alive. - -NOTE: Only messages sent from a user keep the session alive. -This is because only messages coming from a user imply user activity. -Messages received do not imply activity and thus do not renew the session expiration. diff --git a/docs/src/docs/asciidoc/guides/grails3.adoc b/docs/src/docs/asciidoc/guides/grails3.adoc deleted file mode 100644 index 30b31e7..0000000 --- a/docs/src/docs/asciidoc/guides/grails3.adoc +++ /dev/null @@ -1,129 +0,0 @@ -= Spring Session - Grails -Eric Helgeson -:toc: - -This guide describes how to use Spring Session to transparently leverage Redis to back a web application's `HttpSession` when using Grails 3.1 - -NOTE: Grails 3.1 is based off spring boot 1.3 so much of the advanced configuration and options can be found in the boot docs as well. - -NOTE: The completed guide can be found in the <>. - -== Updating Dependencies -Before you use Spring Session, you must ensure to update your dependencies. -We assume you are working with a working Grails 3.1 web profile. -Add the following dependencies: - -.build.gradle -[source,groovy] -[subs="verbatim,attributes"] ----- -dependencies { - compile 'org.springframework.boot:spring-boot-starter-redis' - compile 'org.springframework.session:spring-session:{spring-session-version}' -} ----- - -ifeval::["{version-snapshot}" == "true"] -Since We are using a SNAPSHOT version, we need to ensure to add the Spring Snapshot Maven Repository. -Ensure you have the following in your pom.xml: - -.build.gradle -[source,groovy] ----- -repositories { - maven { - url 'https://repo.spring.io/libs-snapshot' - } -} ----- -endif::[] - -ifeval::["{version-milestone}" == "true"] -Since We are using a Milestone version, we need to ensure to add the Spring Milestone Maven Repository. -Ensure you have the following in your pom.xml: - -.build.gradle -[source,groovy] ----- -repositories { - maven { - url 'https://repo.spring.io/libs-milestone' - } -} ----- -endif::[] - -[[grails3-redis-configuration]] -== Configuring the Redis Connection - -Spring Boot automatically creates a `RedisConnectionFactory` that connects Spring Session to a Redis Server on localhost on port 6379 (default port). -In a production environment you need to ensure to update your configuration to point to your Redis server. -For example, you can include the following in your *application.yml* - -.grails-app/conf/application.yml -[source,yml] ----- -spring: - redis: - host: localhost - password: secret - port: 6397 ----- - -For more information, refer to http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-connecting-to-redis[Connecting to Redis] portion of the Spring Boot documentation. - -[[grails3-sample]] -== Grails 3 Sample Application - -The Grails 3 Sample Application demonstrates how to use Spring Session to transparently leverage Redis to back a web application's `HttpSession` when using Grails. - -[[grails3-running]] -=== Running the Grails 3 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 `JedisConnectionFactory` to point to a Redis server. -==== - ----- -$ ./gradlew :samples:grails3:bootRun ----- - -You should now be able to access the application at http://localhost:8080/test/index - -[[grails3-explore]] -=== Exploring the security Sample Application - -Try using the application. Enter the following to log in: - -* **Username** _user_ -* **Password** _password_ - -Now click the **Login** button. -You should now see a message indicating your are logged in with the user entered previously. -The user's information is stored in Redis rather than Tomcat's `HttpSession` implementation. - -[[grails3-how]] -=== How does it work? - -Instead of using Tomcat's `HttpSession`, we are actually persisting the values in Redis. -Spring Session replaces the `HttpSession` with an implementation that is backed by Redis. -When Spring Security's `SecurityContextPersistenceFilter` saves the `SecurityContext` to the `HttpSession` it is then persisted into Redis. - -When a new `HttpSession` is created, Spring Session creates a cookie named SESSION in your browser that contains the id of your session. -Go ahead and view the cookies (click for help with https://developer.chrome.com/devtools/docs/resources#cookies[Chrome] or https://getfirebug.com/wiki/index.php/Cookies_Panel#Cookies_List[Firefox]). - -If you like, you can easily remove the session using redis-cli. For example, on a Linux based system you can type: - - $ redis-cli keys '*' | xargs redis-cli del - -TIP: The Redis documentation has instructions for http://redis.io/topics/quickstart[installing redis-cli]. - -Alternatively, you can also delete the explicit key. Enter the following into your terminal ensuring to replace `7e8383a4-082c-4ffe-a4bc-c40fd3363c5e` with the value of your SESSION cookie: - - $ redis-cli del spring:session:sessions:7e8383a4-082c-4ffe-a4bc-c40fd3363c5e - -Now visit the application at http://localhost:8080/test/index and observe that we are no longer authenticated. diff --git a/docs/src/docs/asciidoc/guides/java-custom-cookie.adoc b/docs/src/docs/asciidoc/guides/java-custom-cookie.adoc deleted file mode 100644 index ddca7f0..0000000 --- a/docs/src/docs/asciidoc/guides/java-custom-cookie.adoc +++ /dev/null @@ -1,101 +0,0 @@ -= Spring Session - Custom Cookie -Rob Winch -:toc: - -This guide describes how to configure Spring Session to use custom cookies with Java Configuration. -The guide assumes you have already link:./httpsession.html[setup Spring Session in your project]. - -NOTE: The completed guide can be found in the <>. - -[[custom-cookie-spring-configuration]] -== Spring Java Configuration - -Once you have setup Spring Session you can easily customize how the session cookie is written by exposing a `CookieSerializer` as a Spring Bean. -Out of the box, Spring Session comes with `DefaultCookieSerializer`. -Simply exposing the `DefaultCookieSerializer` as a Spring Bean will augment the existing configuration when using configurations like `@EnableRedisHttpSession`. -You can find an example of customizing Spring Session's cookie below: - -[source,java] ----- -include::{samples-dir}javaconfig/custom-cookie/src/main/java/sample/Config.java[tags=cookie-serializer] ----- - -<1> We customize the name of the cookie to be JSESSIONID -<2> We customize the path of the cookie to be "/" (rather than the default of the context root) -<3> We customize the domain name pattern (a regular expression) to be `^.+?\\.(\\w+\\.[a-z]+)$` -This allows sharing a session across domains and applications. -If the regular expression does not match, no domain is set and the existing domain will be used. -If the regular expression matches, the first https://docs.oracle.com/javase/tutorial/essential/regex/groups.html[grouping] will be used as the domain. -This means that a request to https://child.example.com will set the domain to example.com. -However, a request to http://localhost:8080/ or http://192.168.1.100:8080/ will leave the cookie unset and thus still work in development without any changes necessary for production. - -[WARNING] -==== -It is important to note that users should only match on valid domain characters since the domain name is reflected in the response. -This is prevent a malicious user from performing attacks like https://en.wikipedia.org/wiki/HTTP_response_splitting[HTTP Response Splitting]. -==== - -[[custom-cookie-options]] -== Configuration Options - -The configuration options available are: - -* `cookieName` - the name of the cookie to use -Default "SESSION" -* `useSecureCookie` - specify if a secure cookie be used -Default use value of `HttpServletRequest.isSecure()` at the time of creation. -* `cookiePath` - the path of the cookie -Default is context root -* `cookieMaxAge` - specifies the max age of the cookie to be set at the time the session is created. -Default is -1 which indicates the cookie will be removed when the browser is closed. -* `jvmRoute` - specifies a suffix to be appended to the session id and included in the cookie. -Used to identify which JVM to route to for session affinity. -With some implementations (i.e. Redis) this provides no performance benefit. -However, this can help with tracing logs of a particular user. -* `domainName` - allows specifying a specific domain name to be used for the cookie. -This option is simple to understand, but will likely require a different configuration between development and production environments. -See domainNamePattern as an alternative. -* `domainNamePattern` - a case insensitive pattern used to extract the domain name from the `HttpServletRequest#getServerName()`. -The pattern should provide a single grouping used to extract the value of the cookie domain. -If the regular expression does not match, no domain is set and the existing domain will be used. -If the regular expression matches, the first https://docs.oracle.com/javase/tutorial/essential/regex/groups.html[grouping] will be used as the domain. - -[WARNING] -==== -It is important to note that users should only match on valid domain characters since the domain name is reflected in the response. -This is prevent a malicious user from performing attacks like https://en.wikipedia.org/wiki/HTTP_response_splitting[HTTP Response Splitting]. -==== - - -[[custom-cookie-sample]] -== custom-cookie Sample Application - - - -=== Running the custom-cookie 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 `LettuceConnectionFactory` to point to a Redis server. -==== - ----- -$ ./gradlew :samples:custom-cookie:tomcatRun ----- - -You should now be able to access the application at http://localhost:8080/ - -=== Exploring the custom-cookie Sample Application - -Try using the application. Fill out the form with the following information: - -* **Attribute Name:** _username_ -* **Attribute Value:** _rob_ - -Now click the **Set Attribute** button. -You should now see the values displayed in the table. - -If you look at the cookies for the application, you can see the cookie is saved to the custom name of JSESSIONID diff --git a/docs/src/docs/asciidoc/guides/java-hazelcast.adoc b/docs/src/docs/asciidoc/guides/java-hazelcast.adoc deleted file mode 100644 index 22e4504..0000000 --- a/docs/src/docs/asciidoc/guides/java-hazelcast.adoc +++ /dev/null @@ -1,195 +0,0 @@ -= Spring Session and Spring Security with Hazelcast -Tommy Ludwig; Rob Winch -:toc: - -This guide describes how to use Spring Session along with Spring Security using Hazelcast as your data store. -It assumes you have already applied Spring Security to your application. - -NOTE: The completed guide can be found in the <>. - -== Updating Dependencies -Before you use Spring Session, you must ensure to update your dependencies. -If you are using Maven, ensure to add the following dependencies: - -.pom.xml -[source,xml] -[subs="verbatim,attributes"] ----- - - - - - com.hazelcast - hazelcast - {hazelcast-version} - - - org.springframework - spring-web - {spring-version} - - ----- - -ifeval::["{version-snapshot}" == "true"] -Since We are using a SNAPSHOT version, we need to ensure to add the Spring Snapshot Maven Repository. -Ensure you have the following in your pom.xml: - -.pom.xml -[source,xml] ----- - - - - - - spring-snapshot - https://repo.spring.io/libs-snapshot - - ----- -endif::[] - -ifeval::["{version-milestone}" == "true"] -Since We are using a Milestone version, we need to ensure to add the Spring Milestone Maven Repository. -Ensure you have the following in your pom.xml: - -.pom.xml -[source,xml] ----- - -spring-milestone -https://repo.spring.io/libs-milestone - ----- -endif::[] - -// tag::config[] - -[[security-spring-configuration]] -== Spring Configuration - -After adding the required dependencies, we can create our Spring configuration. -The Spring configuration is responsible for creating a Servlet Filter that replaces the `HttpSession` implementation with an implementation backed by Spring Session. -Add the following Spring Configuration: - -[source,java] ----- -include::{docs-test-dir}docs/http/HazelcastHttpSessionConfig.java[tags=config] ----- - -<1> The `@EnableHazelcastHttpSession` annotation creates a Spring Bean with the name of `springSessionRepositoryFilter` that implements Filter. -The filter is what is in charge of replacing the `HttpSession` implementation to be backed by Spring Session. -In this instance Spring Session is backed by Hazelcast. -<2> In order to support retrieval of sessions by principal name index, appropriate `ValueExtractor` needs to be registered. -Spring Session provides `PrincipalNameExtractor` for this purpose. -<3> We create a `HazelcastInstance` that connects Spring Session to Hazelcast. -By default, an embedded instance of Hazelcast is started and connected to by the application. -For more information on configuring Hazelcast, refer to the http://docs.hazelcast.org/docs/latest/manual/html-single/index.html#hazelcast-configuration[reference documentation]. - -== Servlet Container Initialization - -Our <> created a Spring Bean named `springSessionRepositoryFilter` that implements `Filter`. -The `springSessionRepositoryFilter` bean is responsible for replacing the `HttpSession` with a custom implementation that is backed by Spring Session. - -In order for our `Filter` to do its magic, Spring needs to load our `SessionConfig` class. -Since our application is already loading Spring configuration using our `SecurityInitializer` class, we can simply add our `SessionConfig` class to it. - -.src/main/java/sample/SecurityInitializer.java -[source,java] ----- -include::{samples-dir}javaconfig/hazelcast/src/main/java/sample/SecurityInitializer.java[tags=class] ----- - -Last we need to ensure that our Servlet Container (i.e. Tomcat) uses our `springSessionRepositoryFilter` for every request. -It is extremely important that Spring Session's `springSessionRepositoryFilter` is invoked before Spring Security's `springSecurityFilterChain`. -This ensures that the `HttpSession` that Spring Security uses is backed by Spring Session. -Fortunately, Spring Session provides a utility class named `AbstractHttpSessionApplicationInitializer` that makes this extremely easy. -You can find an example below: - -.src/main/java/sample/Initializer.java -[source,java] ----- -include::{samples-dir}javaconfig/hazelcast/src/main/java/sample/Initializer.java[tags=class] ----- - -NOTE: The name of our class (Initializer) does not matter. What is important is that we extend `AbstractHttpSessionApplicationInitializer`. - -By extending `AbstractHttpSessionApplicationInitializer` we ensure that the Spring Bean by the name `springSessionRepositoryFilter` is registered with our Servlet Container for every request before Spring Security's `springSecurityFilterChain`. - -// end::config[] - -[[hazelcast-spring-security-sample]] -== Hazelcast Spring Security Sample Application - -=== Running the Sample Application - -You can run the sample by obtaining the {download-url}[source code] and invoking the following command: - -[NOTE] -==== -Hazelcast will run in embedded mode with your application by default, but if you want to connect -to a stand alone instance instead, you can configure it by following the instructions in the -http://docs.hazelcast.org/docs/latest/manual/html-single/index.html#hazelcast-configuration[reference documentation]. -==== - ----- -$ ./gradlew :samples:hazelcast-spring:tomcatRun ----- - -You should now be able to access the application at http://localhost:8080/ - -=== Exploring the security Sample Application - -Try using the application. Enter the following to log in: - -* **Username** _user_ -* **Password** _password_ - -Now click the **Login** button. -You should now see a message indicating your are logged in with the user entered previously. -The user's information is stored in Hazelcast rather than Tomcat's `HttpSession` implementation. - -=== How does it work? - -Instead of using Tomcat's `HttpSession`, we are actually persisting the values in Hazelcast. -Spring Session replaces the `HttpSession` with an implementation that is backed by a `Map` in Hazelcast. -When Spring Security's `SecurityContextPersistenceFilter` saves the `SecurityContext` to the `HttpSession` it is then persisted into Hazelcast. - -When a new `HttpSession` is created, Spring Session creates a cookie named SESSION in your browser that contains the id of your session. -Go ahead and view the cookies (click for help with https://developer.chrome.com/devtools/docs/resources#cookies[Chrome] or https://getfirebug.com/wiki/index.php/Cookies_Panel#Cookies_List[Firefox]). - -=== Interact with the data store - -If you like, you can remove the session using http://docs.hazelcast.org/docs/latest/manual/html-single/index.html#hazelcast-java-client[a Java client], -http://docs.hazelcast.org/docs/latest/manual/html-single/index.html#other-client-implementations[one of the other clients], or the -http://docs.hazelcast.org/docs/latest/manual/html-single/index.html#management-center[management center]. - -==== Using the console - -For example, using the management center console after connecting to your Hazelcast node: - - default> ns spring:session:sessions - spring:session:sessions> m.clear - -TIP: The Hazelcast documentation has instructions for http://docs.hazelcast.org/docs/latest/manual/html-single/index.html#executing-console-commands[the console]. - -Alternatively, you can also delete the explicit key. Enter the following into the console ensuring to replace `7e8383a4-082c-4ffe-a4bc-c40fd3363c5e` with the value of your SESSION cookie: - - spring:session:sessions> m.remove 7e8383a4-082c-4ffe-a4bc-c40fd3363c5e - -Now visit the application at http://localhost:8080/ and observe that we are no longer authenticated. - -==== Using the REST API - -As described in the other clients section of the documentation, there is a -http://docs.hazelcast.org/docs/latest/manual/html-single/index.html#rest-client[REST API] -provided by the Hazelcast node(s). - -For example, you could delete an individual key as follows (replacing `7e8383a4-082c-4ffe-a4bc-c40fd3363c5e` with the value of your SESSION cookie): - - $ curl -v -X DELETE http://localhost:xxxxx/hazelcast/rest/maps/spring:session:sessions/7e8383a4-082c-4ffe-a4bc-c40fd3363c5e - -TIP: The port number of the Hazelcast node will be printed to the console on startup. Replace `xxxxx` above with the port number. - -Now observe that you are no longer authenticated with this session. diff --git a/docs/src/docs/asciidoc/guides/java-jdbc.adoc b/docs/src/docs/asciidoc/guides/java-jdbc.adoc deleted file mode 100644 index 8fcac96..0000000 --- a/docs/src/docs/asciidoc/guides/java-jdbc.adoc +++ /dev/null @@ -1,152 +0,0 @@ -= Spring Session - HttpSession (Quick Start) -Rob Winch, Vedran Pavić -:toc: - -This guide describes how to use Spring Session to transparently leverage a relational database to back a web application's `HttpSession` with Java Configuration. - -NOTE: The completed guide can be found in the <>. - -== Updating Dependencies -Before you use Spring Session, you must ensure to update your dependencies. -If you are using Maven, ensure to add the following dependencies: - -.pom.xml -[source,xml] -[subs="verbatim,attributes"] ----- - - - - - org.springframework.session - spring-session-jdbc - {spring-session-version} - pom - - - org.springframework - spring-web - {spring-version} - - ----- - -ifeval::["{version-snapshot}" == "true"] -Since we are using a SNAPSHOT version, we need to ensure to add the Spring Snapshot Maven Repository. -Ensure you have the following in your pom.xml: - -.pom.xml -[source,xml] ----- - - - - - - spring-snapshot - https://repo.spring.io/libs-snapshot - - ----- -endif::[] - -ifeval::["{version-milestone}" == "true"] -Since We are using a Milestone version, we need to ensure to add the Spring Milestone Maven Repository. -Ensure you have the following in your pom.xml: - -.pom.xml -[source,xml] ----- - - spring-milestone - https://repo.spring.io/libs-milestone - ----- -endif::[] - -// tag::config[] - -[[httpsession-jdbc-spring-configuration]] -== Spring Java Configuration - -After adding the required dependencies, we can create our Spring configuration. -The Spring configuration is responsible for creating a Servlet Filter that replaces the `HttpSession` implementation with an implementation backed by Spring Session. -Add the following Spring Configuration: - -[source,java] ----- -include::{samples-dir}javaconfig/jdbc/src/main/java/sample/Config.java[tags=class] ----- - -<1> The `@EnableJdbcHttpSession` annotation creates a Spring Bean with the name of `springSessionRepositoryFilter` that implements Filter. -The filter is what is in charge of replacing the `HttpSession` implementation to be backed by Spring Session. -In this instance Spring Session is backed by a relational database. -<2> We create a `dataSource` that connects Spring Session to an embedded instance of H2 database. -We configure the H2 database to create database tables using the SQL script which is included in Spring Session. -<3> We create a `transactionManager` that manages transactions for previously configured `dataSource`. - -For additional information on how to configure data access related concerns, please refer to the http://docs.spring.io/spring/docs/current/spring-framework-reference/html/spring-data-tier.html[Spring Framework Reference Documentation]. - -== Java Servlet Container Initialization - -Our <> created a Spring Bean named `springSessionRepositoryFilter` that implements `Filter`. -The `springSessionRepositoryFilter` bean is responsible for replacing the `HttpSession` with a custom implementation that is backed by Spring Session. - -In order for our `Filter` to do its magic, Spring needs to load our `Config` class. -Last we need to ensure that our Servlet Container (i.e. Tomcat) uses our `springSessionRepositoryFilter` for every request. -Fortunately, Spring Session provides a utility class named `AbstractHttpSessionApplicationInitializer` both of these steps extremely easy. -You can find an example below: - -.src/main/java/sample/Initializer.java -[source,java] ----- -include::{samples-dir}javaconfig/jdbc/src/main/java/sample/Initializer.java[tags=class] ----- - -NOTE: The name of our class (Initializer) does not matter. What is important is that we extend `AbstractHttpSessionApplicationInitializer`. - -<1> The first step is to extend `AbstractHttpSessionApplicationInitializer`. -This ensures that the Spring Bean by the name `springSessionRepositoryFilter` is registered with our Servlet Container for every request. -<2> `AbstractHttpSessionApplicationInitializer` also provides a mechanism to easily ensure Spring loads our `Config`. - -// end::config[] - -[[httpsession-jdbc-sample]] -== httpsession-jdbc Sample Application - -=== Running the httpsession-jdbc Sample Application - -You can run the sample by obtaining the {download-url}[source code] and invoking the following command: - ----- -$ ./gradlew :samples:httpsession-jdbc:tomcatRun ----- - -You should now be able to access the application at http://localhost:8080/ - -=== Exploring the httpsession-jdbc Sample Application - -Try using the application. Fill out the form with the following information: - -* **Attribute Name:** _username_ -* **Attribute Value:** _rob_ - -Now click the **Set Attribute** button. You should now see the values displayed in the table. - -=== How does it work? - -We interact with the standard `HttpSession` in the `SessionServlet` shown below: - -.src/main/java/sample/SessionServlet.java -[source,java] ----- -include::{samples-dir}javaconfig/jdbc/src/main/java/sample/SessionServlet.java[tags=class] ----- - -Instead of using Tomcat's `HttpSession`, we are actually persisting the values in H2 database. -Spring Session creates a cookie named SESSION in your browser that contains the id of your session. -Go ahead and view the cookies (click for help with https://developer.chrome.com/devtools/docs/resources#cookies[Chrome] or https://getfirebug.com/wiki/index.php/Cookies_Panel#Cookies_List[Firefox]). - -If you like, you can easily remove the session using H2 web console available at: http://localhost:8080/h2-console/ (use `jdbc:h2:mem:testdb` for JDBC URL) - -Now visit the application at http://localhost:8080/ and observe that the attribute we added is no longer displayed. diff --git a/docs/src/docs/asciidoc/guides/java-redis.adoc b/docs/src/docs/asciidoc/guides/java-redis.adoc deleted file mode 100644 index b47fcf3..0000000 --- a/docs/src/docs/asciidoc/guides/java-redis.adoc +++ /dev/null @@ -1,171 +0,0 @@ -= Spring Session - HttpSession (Quick Start) -Rob Winch -:toc: - -This guide describes how to use Spring Session to transparently leverage Redis to back a web application's `HttpSession` with Java Configuration. - -NOTE: The completed guide can be found in the <>. - -== Updating Dependencies -Before you use Spring Session, you must ensure to update your dependencies. -If you are using Maven, ensure to add the following dependencies: - -.pom.xml -[source,xml] -[subs="verbatim,attributes"] ----- - - - - - org.springframework.session - spring-session-data-redis - {spring-session-version} - pom - - - io.lettuce - lettuce-core - {lettuce-version} - - - org.springframework - spring-web - {spring-version} - - ----- - -ifeval::["{version-snapshot}" == "true"] -Since we are using a SNAPSHOT version, we need to ensure to add the Spring Snapshot Maven Repository. -Ensure you have the following in your pom.xml: - -.pom.xml -[source,xml] ----- - - - - - - spring-snapshot - https://repo.spring.io/libs-snapshot - - ----- -endif::[] - -ifeval::["{version-milestone}" == "true"] -Since We are using a Milestone version, we need to ensure to add the Spring Milestone Maven Repository. -Ensure you have the following in your pom.xml: - -.pom.xml -[source,xml] ----- - - spring-milestone - https://repo.spring.io/libs-milestone - ----- -endif::[] - -// tag::config[] - -[[httpsession-spring-configuration]] -== Spring Java Configuration - -After adding the required dependencies, we can create our Spring configuration. -The Spring configuration is responsible for creating a Servlet Filter that replaces the `HttpSession` implementation with an implementation backed by Spring Session. -Add the following Spring Configuration: - -[source,java] ----- -include::{samples-dir}javaconfig/redis/src/main/java/sample/Config.java[tags=class] ----- - -<1> The `@EnableRedisHttpSession` annotation creates a Spring Bean with the name of `springSessionRepositoryFilter` that implements Filter. -The filter is what is in charge of replacing the `HttpSession` implementation to be backed by Spring Session. -In this instance Spring Session is backed by Redis. -<2> We create a `RedisConnectionFactory` that connects Spring Session to the Redis Server. -We configure the connection to connect to localhost on the default port (6379) -For more information on configuring Spring Data Redis, refer to the http://docs.spring.io/spring-data/data-redis/docs/current/reference/html/[reference documentation]. - -== Java Servlet Container Initialization - -Our <> created a Spring Bean named `springSessionRepositoryFilter` that implements `Filter`. -The `springSessionRepositoryFilter` bean is responsible for replacing the `HttpSession` with a custom implementation that is backed by Spring Session. - -In order for our `Filter` to do its magic, Spring needs to load our `Config` class. -Last we need to ensure that our Servlet Container (i.e. Tomcat) uses our `springSessionRepositoryFilter` for every request. -Fortunately, Spring Session provides a utility class named `AbstractHttpSessionApplicationInitializer` both of these steps extremely easy. -You can find an example below: - -.src/main/java/sample/Initializer.java -[source,java] ----- -include::{samples-dir}javaconfig/redis/src/main/java/sample/Initializer.java[tags=class] ----- - -NOTE: The name of our class (Initializer) does not matter. What is important is that we extend `AbstractHttpSessionApplicationInitializer`. - -<1> The first step is to extend `AbstractHttpSessionApplicationInitializer`. -This ensures that the Spring Bean by the name `springSessionRepositoryFilter` is registered with our Servlet Container for every request. -<2> `AbstractHttpSessionApplicationInitializer` also provides a mechanism to easily ensure Spring loads our `Config`. - -// end::config[] - -[[httpsession-sample]] -== httpsession Sample Application - - - -=== Running the httpsession 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 `LettuceConnectionFactory` to point to a Redis server. -==== - ----- -$ ./gradlew :samples:httpsession:tomcatRun ----- - -You should now be able to access the application at http://localhost:8080/ - -=== Exploring the httpsession Sample Application - -Try using the application. Fill out the form with the following information: - -* **Attribute Name:** _username_ -* **Attribute Value:** _rob_ - -Now click the **Set Attribute** button. You should now see the values displayed in the table. - -=== How does it work? - -We interact with the standard `HttpSession` in the `SessionServlet` shown below: - -.src/main/java/sample/SessionServlet.java -[source,java] ----- -include::{samples-dir}javaconfig/redis/src/main/java/sample/SessionServlet.java[tags=class] ----- - -Instead of using Tomcat's `HttpSession`, we are actually persisting the values in Redis. -Spring Session creates a cookie named SESSION in your browser that contains the id of your session. -Go ahead and view the cookies (click for help with https://developer.chrome.com/devtools/docs/resources#cookies[Chrome] or https://getfirebug.com/wiki/index.php/Cookies_Panel#Cookies_List[Firefox]). - -If you like, you can easily remove the session using redis-cli. For example, on a Linux based system you can type: - - $ redis-cli keys '*' | xargs redis-cli del - -TIP: The Redis documentation has instructions for http://redis.io/topics/quickstart[installing redis-cli]. - -Alternatively, you can also delete the explicit key. Enter the following into your terminal ensuring to replace `7e8383a4-082c-4ffe-a4bc-c40fd3363c5e` with the value of your SESSION cookie: - - $ redis-cli del spring:session:sessions:7e8383a4-082c-4ffe-a4bc-c40fd3363c5e - -Now visit the application at http://localhost:8080/ and observe that the attribute we added is no longer displayed. diff --git a/docs/src/docs/asciidoc/guides/java-rest.adoc b/docs/src/docs/asciidoc/guides/java-rest.adoc deleted file mode 100644 index aa25d99..0000000 --- a/docs/src/docs/asciidoc/guides/java-rest.adoc +++ /dev/null @@ -1,219 +0,0 @@ -= Spring Session - REST -Rob Winch -:toc: - -This guide describes how to use Spring Session to transparently leverage Redis to back a web application's `HttpSession` when using REST endpoints. - -NOTE: The completed guide can be found in the <>. - -== Updating Dependencies -Before you use Spring Session, you must ensure to update your dependencies. -If you are using Maven, ensure to add the following dependencies: - -.pom.xml -[source,xml] -[subs="verbatim,attributes"] ----- - - - - - org.springframework.session - spring-session-data-redis - {spring-session-version} - pom - - - io.lettuce - lettuce-core - {lettuce-version} - - - org.springframework - spring-web - {spring-version} - - ----- - -ifeval::["{version-snapshot}" == "true"] -Since We are using a SNAPSHOT version, we need to ensure to add the Spring Snapshot Maven Repository. -Ensure you have the following in your pom.xml: - -.pom.xml -[source,xml] ----- - - - - - - spring-snapshot - https://repo.spring.io/libs-snapshot - - ----- -endif::[] - -ifeval::["{version-milestone}" == "true"] -Since We are using a Milestone version, we need to ensure to add the Spring Milestone Maven Repository. -Ensure you have the following in your pom.xml: - -.pom.xml -[source,xml] ----- - - spring-milestone - https://repo.spring.io/libs-milestone - ----- -endif::[] - -// tag::config[] - -[[rest-spring-configuration]] -== Spring Configuration - -After adding the required dependencies, we can create our Spring configuration. -The Spring configuration is responsible for creating a Servlet Filter that replaces the `HttpSession` implementation with an implementation backed by Spring Session. -Add the following Spring Configuration: - -[source,java] ----- -include::{samples-dir}javaconfig/rest/src/main/java/sample/HttpSessionConfig.java[tags=class] ----- - -<1> The `@EnableRedisHttpSession` annotation creates a Spring Bean with the name of `springSessionRepositoryFilter` that implements `Filter`. -The filter is what is in charge of replacing the `HttpSession` implementation to be backed by Spring Session. -In this instance Spring Session is backed by Redis. -<2> We create a `RedisConnectionFactory` that connects Spring Session to the Redis Server. -We configure the connection to connect to localhost on the default port (6379) -For more information on configuring Spring Data Redis, refer to the http://docs.spring.io/spring-data/data-redis/docs/current/reference/html/[reference documentation]. -<3> We customize Spring Session's HttpSession integration to use HTTP headers to convey the current session information instead of cookies. - -== Servlet Container Initialization - -Our <> created a Spring Bean named `springSessionRepositoryFilter` that implements `Filter`. -The `springSessionRepositoryFilter` bean is responsible for replacing the `HttpSession` with a custom implementation that is backed by Spring Session. - -In order for our `Filter` to do its magic, Spring needs to load our `Config` class. We provide the configuration in our Spring `MvcInitializer` as shown below: - -.src/main/java/sample/mvc/MvcInitializer.java -[source,java,indent=0] ----- -include::{samples-dir}javaconfig/rest/src/main/java/sample/mvc/MvcInitializer.java[tags=config] ----- - -Last we need to ensure that our Servlet Container (i.e. Tomcat) uses our `springSessionRepositoryFilter` for every request. -Fortunately, Spring Session provides a utility class named `AbstractHttpSessionApplicationInitializer` that makes this extremely easy. Simply extend the class with the default constructor as shown below: - -.src/main/java/sample/Initializer.java -[source,java] ----- -include::{samples-dir}javaconfig/rest/src/main/java/sample/Initializer.java[tags=class] ----- - -NOTE: The name of our class (Initializer) does not matter. What is important is that we extend `AbstractHttpSessionApplicationInitializer`. - -// end::config[] - -[[rest-sample]] -== rest Sample Application - -=== Running the rest 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 `LettuceConnectionFactory` to point to a Redis server. -==== - ----- -$ ./gradlew :samples:rest:tomcatRun ----- - -You should now be able to access the application at http://localhost:8080/ - -=== Exploring the rest Sample Application - -Try using the application. Use your favorite REST client to request http://localhost:8080/ - - $ curl -v http://localhost:8080/ - -Observe that we are prompted for basic authentication. Provide the following information for the username and password: - -* **Username** *user* -* **Password** *password* - -$ curl -v http://localhost:8080/ -u user:password - -In the output you will notice the following: - ----- -HTTP/1.1 200 OK -... -X-Auth-Token: 0dc1f6e1-c7f1-41ac-8ce2-32b6b3e57aa3 - -{"username":"user"} ----- - -Specifically, we notice the following things about our response: - -* The HTTP Status is now a 200 -* We have a header with the name of *X-Auth-Token* which contains a new session id -* The current username is displayed - -We can now use the *X-Auth-Token* to make another request without providing the username and password again. For example, the following outputs the username just as before: - - $ curl -v http://localhost:8080/ -H "X-Auth-Token: 0dc1f6e1-c7f1-41ac-8ce2-32b6b3e57aa3" - -The only difference is that the session id is not provided in the response headers because we are reusing an existing session. - -If we invalidate the session, then the X-Auth-Token is displayed in the response with an empty value. For example, the following will invalidate our session: - - $ curl -v http://localhost:8080/logout -H "X-Auth-Token: 0dc1f6e1-c7f1-41ac-8ce2-32b6b3e57aa3" - -You will see in the output that the X-Auth-Token provides an empty String indicating that the previous session was invalidated. - ----- -HTTP/1.1 204 No Content -... -X-Auth-Token: ----- - -=== How does it work? - -Spring Security interacts with the standard `HttpSession` in `SecurityContextPersistenceFilter`. - -Instead of using Tomcat's `HttpSession`, Spring Security is now persisting the values in Redis. -Spring Session creates a header named X-Auth-Token in your browser that contains the id of your session. - -If you like, you can easily see that the session is created in Redis. First create a session using the following: - -$ curl -v http://localhost:8080/ -u user:password - -In the output you will notice the following: - ----- -HTTP/1.1 200 OK -... -X-Auth-Token: 7e8383a4-082c-4ffe-a4bc-c40fd3363c5e - -{"username":"user"} ----- - -Now remove the session using redis-cli. For example, on a Linux based system you can type: - - $ redis-cli keys '*' | xargs redis-cli del - -TIP: The Redis documentation has instructions for http://redis.io/topics/quickstart[installing redis-cli]. - -Alternatively, you can also delete the explicit key. Enter the following into your terminal ensuring to replace `7e8383a4-082c-4ffe-a4bc-c40fd3363c5e` with the value of your SESSION cookie: - - $ redis-cli del spring:session:sessions:7e8383a4-082c-4ffe-a4bc-c40fd3363c5e - -We can now use the *X-Auth-Token* to make another request with the session we deleted and observe we are prompted for a authentication. For example, the following returns an HTTP 401: - - $ curl -v http://localhost:8080/ -H "X-Auth-Token: 0dc1f6e1-c7f1-41ac-8ce2-32b6b3e57aa3" diff --git a/docs/src/docs/asciidoc/guides/java-security.adoc b/docs/src/docs/asciidoc/guides/java-security.adoc deleted file mode 100644 index 7187b4e..0000000 --- a/docs/src/docs/asciidoc/guides/java-security.adoc +++ /dev/null @@ -1,173 +0,0 @@ -= Spring Session and Spring Security -Rob Winch -:toc: - -This guide describes how to use Spring Session along with Spring Security. -It assumes you have already applied Spring Security to your application. - -NOTE: The completed guide can be found in the <>. - -== Updating Dependencies -Before you use Spring Session, you must ensure to update your dependencies. -If you are using Maven, ensure to add the following dependencies: - -.pom.xml -[source,xml] -[subs="verbatim,attributes"] ----- - - - - - org.springframework.session - spring-session-data-redis - {spring-session-version} - pom - - - io.lettuce - lettuce-core - {lettuce-version} - - - org.springframework - spring-web - {spring-version} - - ----- - -ifeval::["{version-snapshot}" == "true"] -Since We are using a SNAPSHOT version, we need to ensure to add the Spring Snapshot Maven Repository. -Ensure you have the following in your pom.xml: - -.pom.xml -[source,xml] ----- - - - - - - spring-snapshot - https://repo.spring.io/libs-snapshot - - ----- -endif::[] - -ifeval::["{version-milestone}" == "true"] -Since We are using a Milestone version, we need to ensure to add the Spring Milestone Maven Repository. -Ensure you have the following in your pom.xml: - -.pom.xml -[source,xml] ----- - -spring-milestone -https://repo.spring.io/libs-milestone - ----- -endif::[] - -[[security-spring-configuration]] -== Spring Configuration - -After adding the required dependencies, we can create our Spring configuration. -The Spring configuration is responsible for creating a Servlet Filter that replaces the `HttpSession` implementation with an implementation backed by Spring Session. -Add the following Spring Configuration: - -[source,java] ----- -include::{samples-dir}javaconfig/security/src/main/java/sample/Config.java[tags=class] ----- - -<1> The `@EnableRedisHttpSession` annotation creates a Spring Bean with the name of `springSessionRepositoryFilter` that implements Filter. -The filter is what is in charge of replacing the `HttpSession` implementation to be backed by Spring Session. -In this instance Spring Session is backed by Redis. -<2> We create a `RedisConnectionFactory` that connects Spring Session to the Redis Server. -We configure the connection to connect to localhost on the default port (6379) -For more information on configuring Spring Data Redis, refer to the http://docs.spring.io/spring-data/data-redis/docs/current/reference/html/[reference documentation]. - -== Servlet Container Initialization - -Our <> created a Spring Bean named `springSessionRepositoryFilter` that implements `Filter`. -The `springSessionRepositoryFilter` bean is responsible for replacing the `HttpSession` with a custom implementation that is backed by Spring Session. - -In order for our `Filter` to do its magic, Spring needs to load our `Config` class. -Since our application is already loading Spring configuration using our `SecurityInitializer` class, we can simply add our Config class to it. - -.src/main/java/sample/SecurityInitializer.java -[source,java] ----- -include::{samples-dir}javaconfig/security/src/main/java/sample/SecurityInitializer.java[tags=class] ----- - -Last we need to ensure that our Servlet Container (i.e. Tomcat) uses our `springSessionRepositoryFilter` for every request. -It is extremely important that Spring Session's `springSessionRepositoryFilter` is invoked before Spring Security's `springSecurityFilterChain`. -This ensures that the `HttpSession` that Spring Security uses is backed by Spring Session. -Fortunately, Spring Session provides a utility class named `AbstractHttpSessionApplicationInitializer` that makes this extremely easy. -You can find an example below: - -.src/main/java/sample/Initializer.java -[source,java] ----- -include::{samples-dir}javaconfig/security/src/main/java/sample/Initializer.java[tags=class] ----- - -NOTE: The name of our class (Initializer) does not matter. What is important is that we extend `AbstractHttpSessionApplicationInitializer`. - -By extending `AbstractHttpSessionApplicationInitializer` we ensure that the Spring Bean by the name `springSessionRepositoryFilter` is registered with our Servlet Container for every request before Spring Security's `springSecurityFilterChain` . - -[[security-sample]] -== security Sample Application - - - -=== Running the security 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 `LettuceConnectionFactory` to point to a Redis server. -==== - ----- -$ ./gradlew :samples:security:tomcatRun ----- - -You should now be able to access the application at http://localhost:8080/ - -=== Exploring the security Sample Application - -Try using the application. Enter the following to log in: - -* **Username** _user_ -* **Password** _password_ - -Now click the **Login** button. -You should now see a message indicating your are logged in with the user entered previously. -The user's information is stored in Redis rather than Tomcat's `HttpSession` implementation. - -=== How does it work? - -Instead of using Tomcat's `HttpSession`, we are actually persisting the values in Redis. -Spring Session replaces the `HttpSession` with an implementation that is backed by Redis. -When Spring Security's `SecurityContextPersistenceFilter` saves the `SecurityContext` to the `HttpSession` it is then persisted into Redis. - -When a new `HttpSession` is created, Spring Session creates a cookie named SESSION in your browser that contains the id of your session. -Go ahead and view the cookies (click for help with https://developer.chrome.com/devtools/docs/resources#cookies[Chrome] or https://getfirebug.com/wiki/index.php/Cookies_Panel#Cookies_List[Firefox]). - -If you like, you can easily remove the session using redis-cli. For example, on a Linux based system you can type: - - $ redis-cli keys '*' | xargs redis-cli del - -TIP: The Redis documentation has instructions for http://redis.io/topics/quickstart[installing redis-cli]. - -Alternatively, you can also delete the explicit key. Enter the following into your terminal ensuring to replace `7e8383a4-082c-4ffe-a4bc-c40fd3363c5e` with the value of your SESSION cookie: - - $ redis-cli del spring:session:sessions:7e8383a4-082c-4ffe-a4bc-c40fd3363c5e - -Now visit the application at http://localhost:8080/ and observe that we are no longer authenticated. 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 334ce19..0000000 --- a/docs/src/docs/asciidoc/guides/java-users.adoc +++ /dev/null @@ -1,161 +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 `LettuceConnectionFactory` to point to a Redis server. -==== - ----- -$ ./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/guides/xml-jdbc.adoc b/docs/src/docs/asciidoc/guides/xml-jdbc.adoc deleted file mode 100644 index 3931d72..0000000 --- a/docs/src/docs/asciidoc/guides/xml-jdbc.adoc +++ /dev/null @@ -1,162 +0,0 @@ -= Spring Session - HttpSession (Quick Start) -Rob Winch, Vedran Pavić -:toc: - -This guide describes how to use Spring Session to transparently leverage a relational to back a web application's `HttpSession` with XML based configuration. - -NOTE: The completed guide can be found in the <>. - -== Updating Dependencies -Before you use Spring Session, you must ensure to update your dependencies. -If you are using Maven, ensure to add the following dependencies: - -.pom.xml -[source,xml] -[subs="verbatim,attributes"] ----- - - - - - org.springframework.session - spring-session-jdbc - {spring-session-version} - pom - - - org.springframework - spring-web - {spring-version} - - ----- - -ifeval::["{version-snapshot}" == "true"] -Since we are using a SNAPSHOT version, we need to ensure to add the Spring Snapshot Maven Repository. -Ensure you have the following in your pom.xml: - -.pom.xml -[source,xml] ----- - - - - - - spring-snapshot - https://repo.spring.io/libs-snapshot - - ----- -endif::[] - -ifeval::["{version-milestone}" == "true"] -Since We are using a Milestone version, we need to ensure to add the Spring Milestone Maven Repository. -Ensure you have the following in your pom.xml: - -.pom.xml -[source,xml] ----- - - spring-milestone - https://repo.spring.io/libs-milestone - ----- -endif::[] - -// tag::config[] - -[[httpsession-jdbc-xml-spring-configuration]] -== Spring XML Configuration - -After adding the required dependencies, we can create our Spring configuration. -The Spring configuration is responsible for creating a Servlet Filter that replaces the `HttpSession` implementation with an implementation backed by Spring Session. -Add the following Spring Configuration: - -.src/main/webapp/WEB-INF/spring/session.xml -[source,xml,indent=0] ----- -include::{samples-dir}xml/jdbc/src/main/webapp/WEB-INF/spring/session.xml[tags=beans] ----- - -<1> We use the combination of `` and `JdbcHttpSessionConfiguration` because Spring Session does not yet provide XML Namespace support (see https://github.com/spring-projects/spring-session/issues/104[gh-104]). -This creates a Spring Bean with the name of `springSessionRepositoryFilter` that implements Filter. -The filter is what is in charge of replacing the `HttpSession` implementation to be backed by Spring Session. -In this instance Spring Session is backed by a relational database. -<2> We create a `dataSource` that connects Spring Session to an embedded instance of H2 database. -We configure the H2 database to create database tables using the SQL script which is included in Spring Session. -<3> We create a `transactionManager` that manages transactions for previously configured `dataSource`. - -For additional information on how to configure data access related concerns, please refer to the http://docs.spring.io/spring/docs/current/spring-framework-reference/html/spring-data-tier.html[Spring Framework Reference Documentation]. - -== XML Servlet Container Initialization - -Our <> created a Spring Bean named `springSessionRepositoryFilter` that implements `Filter`. -The `springSessionRepositoryFilter` bean is responsible for replacing the `HttpSession` with a custom implementation that is backed by Spring Session. - -In order for our `Filter` to do its magic, we need to instruct Spring to load our `session.xml` configuration. -We do this with the following configuration: - - -.src/main/webapp/WEB-INF/web.xml -[source,xml,indent=0] ----- -include::{samples-dir}xml/jdbc/src/main/webapp/WEB-INF/web.xml[tags=context-param] -include::{samples-dir}xml/jdbc/src/main/webapp/WEB-INF/web.xml[tags=listeners] ----- - -The http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#context-create[ContextLoaderListener] reads the contextConfigLocation and picks up our session.xml configuration. - -Last we need to ensure that our Servlet Container (i.e. Tomcat) uses our `springSessionRepositoryFilter` for every request. -The following snippet performs this last step for us: - -.src/main/webapp/WEB-INF/web.xml -[source,xml,indent=0] ----- -include::{samples-dir}xml/jdbc/src/main/webapp/WEB-INF/web.xml[tags=springSessionRepositoryFilter] ----- - -The http://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/filter/DelegatingFilterProxy.html[DelegatingFilterProxy] will look up a Bean by the name of `springSessionRepositoryFilter` and cast it to a `Filter`. -For every request that `DelegatingFilterProxy` is invoked, the `springSessionRepositoryFilter` will be invoked. - -// end::config[] - -[[httpsession-jdbc-xml-sample]] -== httpsession-jdbc-xml Sample Application - -=== Running the httpsession-jdbc-xml Sample Application - -You can run the sample by obtaining the {download-url}[source code] and invoking the following command: - ----- -$ ./gradlew :samples:httpsession-jdbc-xml:tomcatRun ----- - -You should now be able to access the application at http://localhost:8080/ - -=== Exploring the httpsession-jdbc-xml Sample Application - -Try using the application. Fill out the form with the following information: - -* **Attribute Name:** _username_ -* **Attribute Value:** _rob_ - -Now click the **Set Attribute** button. You should now see the values displayed in the table. - -=== How does it work? - -We interact with the standard `HttpSession` in the `SessionServlet` shown below: - -.src/main/java/sample/SessionServlet.java -[source,java] ----- -include::{samples-dir}xml/jdbc/src/main/java/sample/SessionServlet.java[tags=class] ----- - -Instead of using Tomcat's `HttpSession`, we are actually persisting the values in H2 database. -Spring Session creates a cookie named SESSION in your browser that contains the id of your session. -Go ahead and view the cookies (click for help with https://developer.chrome.com/devtools/docs/resources#cookies[Chrome] or https://getfirebug.com/wiki/index.php/Cookies_Panel#Cookies_List[Firefox]). - -If you like, you can easily remove the session using H2 web console available at: http://localhost:8080/h2-console/ (use `jdbc:h2:mem:testdb` for JDBC URL) - -Now visit the application at http://localhost:8080/ and observe that the attribute we added is no longer displayed. diff --git a/docs/src/docs/asciidoc/guides/xml-redis.adoc b/docs/src/docs/asciidoc/guides/xml-redis.adoc deleted file mode 100644 index 6581e6a..0000000 --- a/docs/src/docs/asciidoc/guides/xml-redis.adoc +++ /dev/null @@ -1,179 +0,0 @@ -= Spring Session - HttpSession (Quick Start) -Rob Winch -:toc: - -This guide describes how to use Spring Session to transparently leverage Redis to back a web application's `HttpSession` with XML based configuration. - -NOTE: The completed guide can be found in the <>. - -== Updating Dependencies -Before you use Spring Session, you must ensure to update your dependencies. -If you are using Maven, ensure to add the following dependencies: - -.pom.xml -[source,xml] -[subs="verbatim,attributes"] ----- - - - - - org.springframework.session - spring-session-data-redis - {spring-session-version} - pom - - - io.lettuce - lettuce-core - {lettuce-version} - - - org.springframework - spring-web - {spring-version} - - ----- - -ifeval::["{version-snapshot}" == "true"] -Since we are using a SNAPSHOT version, we need to ensure to add the Spring Snapshot Maven Repository. -Ensure you have the following in your pom.xml: - -.pom.xml -[source,xml] ----- - - - - - - spring-snapshot - https://repo.spring.io/libs-snapshot - - ----- -endif::[] - -ifeval::["{version-milestone}" == "true"] -Since We are using a Milestone version, we need to ensure to add the Spring Milestone Maven Repository. -Ensure you have the following in your pom.xml: - -.pom.xml -[source,xml] ----- - - spring-milestone - https://repo.spring.io/libs-milestone - ----- -endif::[] - -// tag::config[] - -[[httpsession-xml-spring-configuration]] -== Spring XML Configuration - -After adding the required dependencies, we can create our Spring configuration. -The Spring configuration is responsible for creating a Servlet Filter that replaces the `HttpSession` implementation with an implementation backed by Spring Session. -Add the following Spring Configuration: - -.src/main/webapp/WEB-INF/spring/session.xml -[source,xml,indent=0] ----- -include::{samples-dir}xml/redis/src/main/webapp/WEB-INF/spring/session.xml[tags=beans] ----- - -<1> We use the combination of `` and `RedisHttpSessionConfiguration` because Spring Session does not yet provide XML Namespace support (see https://github.com/spring-projects/spring-session/issues/104[gh-104]). -This creates a Spring Bean with the name of `springSessionRepositoryFilter` that implements Filter. -The filter is what is in charge of replacing the `HttpSession` implementation to be backed by Spring Session. -In this instance Spring Session is backed by Redis. -<2> We create a `RedisConnectionFactory` that connects Spring Session to the Redis Server. -We configure the connection to connect to localhost on the default port (6379) -For more information on configuring Spring Data Redis, refer to the http://docs.spring.io/spring-data/data-redis/docs/current/reference/html/[reference documentation]. - -== XML Servlet Container Initialization - -Our <> created a Spring Bean named `springSessionRepositoryFilter` that implements `Filter`. -The `springSessionRepositoryFilter` bean is responsible for replacing the `HttpSession` with a custom implementation that is backed by Spring Session. - -In order for our `Filter` to do its magic, we need to instruct Spring to load our `session.xml` configuration. -We do this with the following configuration: - - -.src/main/webapp/WEB-INF/web.xml -[source,xml,indent=0] ----- -include::{samples-dir}xml/redis/src/main/webapp/WEB-INF/web.xml[tags=context-param] -include::{samples-dir}xml/redis/src/main/webapp/WEB-INF/web.xml[tags=listeners] ----- - -The http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#context-create[ContextLoaderListener] reads the contextConfigLocation and picks up our session.xml configuration. - -Last we need to ensure that our Servlet Container (i.e. Tomcat) uses our `springSessionRepositoryFilter` for every request. -The following snippet performs this last step for us: - -.src/main/webapp/WEB-INF/web.xml -[source,xml,indent=0] ----- -include::{samples-dir}xml/redis/src/main/webapp/WEB-INF/web.xml[tags=springSessionRepositoryFilter] ----- - -The http://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/filter/DelegatingFilterProxy.html[DelegatingFilterProxy] will look up a Bean by the name of `springSessionRepositoryFilter` and cast it to a `Filter`. -For every request that `DelegatingFilterProxy` is invoked, the `springSessionRepositoryFilter` will be invoked. - -// end::config[] - -[[httpsession-xml-sample]] -== httpsession-xml Sample Application - -=== Running the httpsession-xml 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 `LettuceConnectionFactory` to point to a Redis server. -==== - ----- -$ ./gradlew :samples:httpsession-xml:tomcatRun ----- - -You should now be able to access the application at http://localhost:8080/ - -=== Exploring the httpsession-xml Sample Application - -Try using the application. Fill out the form with the following information: - -* **Attribute Name:** _username_ -* **Attribute Value:** _rob_ - -Now click the **Set Attribute** button. You should now see the values displayed in the table. - -=== How does it work? - -We interact with the standard `HttpSession` in the `SessionServlet` shown below: - -.src/main/java/sample/SessionServlet.java -[source,java] ----- -include::{samples-dir}xml/redis/src/main/java/sample/SessionServlet.java[tags=class] ----- - -Instead of using Tomcat's `HttpSession`, we are actually persisting the values in Redis. -Spring Session creates a cookie named SESSION in your browser that contains the id of your session. -Go ahead and view the cookies (click for help with https://developer.chrome.com/devtools/docs/resources#cookies[Chrome] or https://getfirebug.com/wiki/index.php/Cookies_Panel#Cookies_List[Firefox]). - -If you like, you can easily remove the session using redis-cli. For example, on a Linux based system you can type: - - $ redis-cli keys '*' | xargs redis-cli del - -TIP: The Redis documentation has instructions for http://redis.io/topics/quickstart[installing redis-cli]. - -Alternatively, you can also delete the explicit key. Enter the following into your terminal ensuring to replace `7e8383a4-082c-4ffe-a4bc-c40fd3363c5e` with the value of your SESSION cookie: - - $ redis-cli del spring:session:sessions:7e8383a4-082c-4ffe-a4bc-c40fd3363c5e - -Now visit the application at http://localhost:8080/ and observe that the attribute we added is no longer displayed. diff --git a/gradle.properties b/gradle.properties deleted file mode 100644 index 646469f..0000000 --- a/gradle.properties +++ /dev/null @@ -1,3 +0,0 @@ -version=2.0.0.BUILD-SNAPSHOT -springBootVersion=2.0.0.BUILD-SNAPSHOT -springIoVersion=Cairo-BUILD-SNAPSHOT \ No newline at end of file diff --git a/gradle/bom.gradle b/gradle/bom.gradle deleted file mode 100644 index f7d6c6b..0000000 --- a/gradle/bom.gradle +++ /dev/null @@ -1,3 +0,0 @@ -sonarqube { - skipProject = true -} diff --git a/gradle/dependency-management.properties b/gradle/dependency-management.properties deleted file mode 100644 index 01a2583..0000000 --- a/gradle/dependency-management.properties +++ /dev/null @@ -1,9 +0,0 @@ -com.maxmind.geoip2\:geoip2=2.3.1 -edu.umd.cs.mtc\:multithreadedtc=1.01 -org.springframework.shell\:spring-shell=1.1.0.RELEASE -org.webjars\:bootstrap=2.3.2 -org.webjars\:html5shiv=3.7.3 -org.webjars\:knockout=2.3.0 -org.webjars\:sockjs-client=0.3.4 -org.webjars\:stomp-websocket=2.3.0 -org.webjars\:webjars-taglib=0.3 \ No newline at end of file diff --git a/gradle/ide.gradle b/gradle/ide.gradle deleted file mode 100644 index f28e88d..0000000 --- a/gradle/ide.gradle +++ /dev/null @@ -1,60 +0,0 @@ -import org.gradle.plugins.ide.eclipse.model.ProjectDependency -import org.gradle.plugins.ide.eclipse.model.SourceFolder - - -apply plugin: "propdeps-eclipse" -apply plugin: "propdeps-idea" - -eclipse { - jdt { - javaRuntimeName = "J2SE-1.5" - } -} - -eclipse.project.buildCommand "net.sf.eclipsecs.core.CheckstyleBuilder" -eclipse.project.natures "net.sf.eclipsecs.core.CheckstyleNature" - -// Include project specific settings -task eclipseCheckstyle(type: Copy) { - from rootProject.files( - "eclipse/.checkstyle") - into project.projectDir - expand(configDir: rootProject.file('config/checkstyle').absolutePath) -} - -task eclipseSettings(type: Copy) { - from rootProject.files( - "eclipse/org.eclipse.jdt.ui.prefs", - "eclipse/org.eclipse.wst.common.project.facet.core.xml") - into project.file('.settings/') - outputs.upToDateWhen { false } -} - -task eclipseWstComponent(type: Copy) { - from rootProject.files( - "eclipse/org.eclipse.wst.common.component") - into project.file('.settings/') - expand(deployname: project.name) - outputs.upToDateWhen { false } -} - -task eclipseJdtPrepare(type: Copy) { - from rootProject.file("eclipse/org.eclipse.jdt.core.prefs") - into project.file(".settings/") - outputs.upToDateWhen { false } -} - -task cleanEclipseJdtUi(type: Delete) { - delete project.file(".settings/org.eclipse.jdt.core.prefs") - delete project.file(".settings/org.eclipse.jdt.ui.prefs") - delete project.file(".settings/org.eclipse.wst.common.component") - delete project.file(".settings/org.eclipse.wst.common.project.facet.core.xml") -} - -task eclipseConfiguration(dependsOn: [eclipseCheckstyle, eclipseJdtPrepare, eclipseSettings, eclipseWstComponent]) { - group 'ide' -} - -tasks["eclipseJdt"].dependsOn(eclipseJdtPrepare) -tasks["cleanEclipse"].dependsOn(cleanEclipseJdtUi) -tasks["eclipse"].dependsOn(eclipseConfiguration) \ No newline at end of file diff --git a/gradle/java.gradle b/gradle/java.gradle deleted file mode 100644 index fb6213d..0000000 --- a/gradle/java.gradle +++ /dev/null @@ -1,92 +0,0 @@ -apply plugin: 'java' -apply plugin: 'groovy' -apply plugin: 'javadocHotfix' -apply plugin: 'eclipse-wtp' -apply plugin: 'propdeps' -apply plugin: 'propdeps-idea' -apply plugin: 'propdeps-eclipse' -apply plugin: 'com.github.ben-manes.versions' -apply plugin: 'checkstyle' -apply from: IDE_GRADLE - -group = 'org.springframework.session' - -sourceCompatibility = 1.8 -targetCompatibility = 1.8 - -ext.springIoVersion = project.hasProperty('platformVersion') ? platformVersion : 'Cairo-BUILD-SNAPSHOT' - -ext.seleniumDependencies = [ - "org.seleniumhq.selenium:htmlunit-driver:$htmlUnitVersion", - "org.seleniumhq.selenium:selenium-firefox-driver:$seleniumVersion" -] - -ext.jstlDependencies = [ - "javax.servlet.jsp.jstl:javax.servlet.jsp.jstl-api:$jstlVersion", - "org.apache.taglibs:taglibs-standard-jstlel:1.2.1" -] - -repositories { - mavenCentral() - maven { url 'https://repo.spring.io/libs-snapshot' } - maven { url 'https://oss.sonatype.org/content/repositories/snapshots' } -} - -configurations.all { - resolutionStrategy.eachDependency { DependencyResolveDetails details -> - if (details.requested.group == 'org.springframework') { - details.useVersion springVersion - } - } -} -// Integration test setup -configurations { - integrationTestCompile { - extendsFrom testCompile, optional, provided - } - integrationTestRuntime { - extendsFrom integrationTestCompile, testRuntime - } -} - -sourceSets { - integrationTest { - java.srcDir file('src/integration-test/java') - groovy.srcDirs file('src/integration-test/groovy') - resources.srcDir file('src/integration-test/resources') - compileClasspath = sourceSets.main.output + sourceSets.test.output + configurations.integrationTestCompile - runtimeClasspath = output + compileClasspath + configurations.integrationTestRuntime - } -} - -task integrationTest(type: Test, dependsOn: jar) { - testClassesDir = sourceSets.integrationTest.output.classesDir - logging.captureStandardOutput(LogLevel.INFO) - classpath = sourceSets.integrationTest.runtimeClasspath - maxParallelForks = 1 - reports { - html.destination = project.file("$project.buildDir/reports/integration-tests/") - junitXml.destination = project.file("$project.buildDir/integration-test-results/") - } -} -check.dependsOn integrationTest - -checkstyle { - configFile = rootProject.file('config/checkstyle/checkstyle.xml') - configProperties.configDir = configFile.parentFile - toolVersion = '6.16.1' -} - -task checkstyle { - dependsOn project.tasks.findAll { task -> task.name.matches('checkstyle\\w+') } -} - -eclipse { - classpath { - plusConfigurations += [ configurations.integrationTestCompile ] - } -} - -project.idea.module { - scopes.TEST.plus += [project.configurations.integrationTestRuntime] -} diff --git a/gradle/publish-maven.gradle b/gradle/publish-maven.gradle deleted file mode 100644 index 89fc767..0000000 --- a/gradle/publish-maven.gradle +++ /dev/null @@ -1,51 +0,0 @@ -apply plugin: 'propdeps-maven' - -install { - repositories.mavenInstaller { - customizePom(pom, project) - } -} - -def customizePom(pom, gradleProject) { - pom.whenConfigured { generatedPom -> - - // sort to make pom dependencies order consistent to ease comparison of older poms - generatedPom.dependencies = generatedPom.dependencies.sort { dep -> - "$dep.scope:$dep.groupId:$dep.artifactId" - } - - // add all items necessary for maven central publication - generatedPom.project { - name = gradleProject.description - description = gradleProject.description - url = "https://github.com/spring-projects/spring-session" - organization { - name = "Spring IO" - url = "http://projects.spring.io/spring-session" - } - licenses { - license { - name "The Apache Software License, Version 2.0" - url "http://www.apache.org/licenses/LICENSE-2.0.txt" - distribution "repo" - } - } - scm { - url = "https://github.com/spring-projects/spring-session" - connection = "scm:git:git://github.com/spring-projects/spring-session" - developerConnection = "scm:git:git://github.com/spring-projects/spring-session" - } - developers { - developer { - id = "rwinch" - name = "Rob Winch" - email = "rwinch@pivotal.io" - } - } - issueManagement { - system = "GitHub" - url = "https://github.com/spring-projects/spring-session/issues" - } - } - } -} \ No newline at end of file diff --git a/gradle/sample.gradle b/gradle/sample.gradle deleted file mode 100644 index c2170ae..0000000 --- a/gradle/sample.gradle +++ /dev/null @@ -1,4 +0,0 @@ -tasks.findByPath("artifactoryPublish")?.enabled = false -sonarqube { - skipProject = true -} \ No newline at end of file diff --git a/gradle/spring3.gradle b/gradle/spring3.gradle deleted file mode 100644 index 1488083..0000000 --- a/gradle/spring3.gradle +++ /dev/null @@ -1,39 +0,0 @@ -configurations { - spring3TestRuntime.extendsFrom testRuntime -} - -configurations.spring3TestRuntime { - resolutionStrategy.eachDependency { DependencyResolveDetails details -> - if (details.requested.group == 'org.springframework' - && details.requested.name != 'spring-websocket' - && details.requested.name != 'spring-messaging') { - details.useVersion '3.2.18.RELEASE' - } - if (details.requested.group == 'org.springframework.data') { - if (details.requested.name == 'spring-data-commons') { - details.useVersion '1.12.1.RELEASE' - } - if (details.requested.name == 'spring-data-keyvalue') { - details.useVersion '1.1.1.RELEASE' - } - if (details.requested.name == 'spring-data-mongodb') { - details.useVersion '1.9.1.RELEASE' - } - if (details.requested.name == 'spring-data-redis') { - details.useVersion '1.7.1.RELEASE' - } - } - } -} - -task spring3Test(type: Test) { - jvmArgs = ['-ea', '-Xmx500m', '-XX:MaxPermSize=128M'] - classpath = sourceSets.test.output + sourceSets.main.output + configurations.spring3TestRuntime - exclude "org/springframework/session/web/socket/**" - reports { - html.destination = project.file("$buildDir/spring3-test-results/") - junitXml.destination = project.file("$buildDir/reports/spring3-tests/") - } -} - -//check.dependsOn spring3Test diff --git a/gradle/tomcat.gradle b/gradle/tomcat.gradle deleted file mode 100644 index bbc0861..0000000 --- a/gradle/tomcat.gradle +++ /dev/null @@ -1,61 +0,0 @@ -buildscript { - repositories { - maven { url "https://repo.spring.io/plugins-release" } - } - dependencies { - classpath("com.bmuschko:gradle-tomcat-plugin:2.2.5") - } -} - -apply plugin: 'war' -apply plugin: 'com.bmuschko.tomcat' - -[tomcatRun,tomcatRunWar]*.contextPath = '/' - - -task integrationTomcatRun(type: com.bmuschko.gradle.tomcat.tasks.TomcatRun) { - onlyIf { !sourceSets.integrationTest.allSource.empty } - contextPath = tomcatRun.contextPath - daemon = true - tomcatClasspath = tomcatRun.tomcatClasspath - webAppClasspath = tomcatRun.webAppClasspath - webAppSourceDirectory = tomcatRun.webAppSourceDirectory - doFirst { - def mainOutputDir = project.sourceSets.main.output.classesDir - if(mainOutputDir) { - classesDirectory = mainOutputDir - } - // delay reserving ports to ensure they are still available - def ports = reservePorts(3) - httpPort = ports[0] - ajpPort = ports[1] - stopPort = ports[2] - - System.setProperty('spring.session.redis.namespace',project.name) - } -} - -task integrationTomcatStop(type: com.bmuschko.gradle.tomcat.tasks.TomcatStop) { - onlyIf { !sourceSets.integrationTest.allSource.empty } - doFirst { - stopPort = integrationTomcatRun.stopPort - } -} - -integrationTest { - dependsOn integrationTomcatRun - doFirst { - systemProperties['tomcat.port'] = integrationTomcatRun.httpPort - } - finalizedBy integrationTomcatStop -} - -def reservePorts(int count) { - def sockets = [] - for(int i in 1..count) { - sockets << new ServerSocket(0) - } - def result = sockets*.localPort - sockets*.close() - result -} diff --git a/gradle/tomcat6.gradle b/gradle/tomcat6.gradle deleted file mode 100644 index 964cb64..0000000 --- a/gradle/tomcat6.gradle +++ /dev/null @@ -1,8 +0,0 @@ -apply from: TOMCAT_GRADLE - -dependencies { - def tomcatVersion = '6.0.43' - tomcat "org.apache.tomcat:catalina:${tomcatVersion}", - "org.apache.tomcat:coyote:${tomcatVersion}", - "org.apache.tomcat:jasper:${tomcatVersion}" -} \ No newline at end of file diff --git a/gradle/tomcat7.gradle b/gradle/tomcat7.gradle deleted file mode 100644 index 4f41f94..0000000 --- a/gradle/tomcat7.gradle +++ /dev/null @@ -1,8 +0,0 @@ -apply from: TOMCAT_GRADLE - -dependencies { - def tomcatVersion = '7.0.59' - tomcat "org.apache.tomcat.embed:tomcat-embed-core:${tomcatVersion}", - "org.apache.tomcat.embed:tomcat-embed-logging-juli:${tomcatVersion}", - "org.apache.tomcat.embed:tomcat-embed-jasper:${tomcatVersion}" -} diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 6ffa237..0000000 Binary files a/gradle/wrapper/gradle-wrapper.jar and /dev/null differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 5774f60..0000000 --- a/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,6 +0,0 @@ -#Wed Jan 11 10:54:44 CST 2017 -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-3.5-bin.zip diff --git a/gradlew b/gradlew deleted file mode 100755 index 9aa616c..0000000 --- a/gradlew +++ /dev/null @@ -1,169 +0,0 @@ -#!/usr/bin/env bash - -############################################################################## -## -## Gradle start up script for UN*X -## -############################################################################## - -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" - -warn ( ) { - echo "$*" -} - -die ( ) { - echo - echo "$*" - echo - exit 1 -} - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=$((i+1)) - done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac -fi - -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") -} -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" - -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [[ "$(uname)" == "Darwin" ]] && [[ "$HOME" == "$PWD" ]]; then - cd "$(dirname "$0")" -fi - -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/gradlew.bat b/gradlew.bat deleted file mode 100644 index e95643d..0000000 --- a/gradlew.bat +++ /dev/null @@ -1,84 +0,0 @@ -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..cedae09 --- /dev/null +++ b/pom.xml @@ -0,0 +1,443 @@ + + + 4.0.0 + + org.springframework.session + spring-session-data-mongodb + 2.0.0.BUILD-SNAPSHOT + + Spring Session MongoDB + https://github.com/spring-projects/spring-session-data-mongodb + + Persist session data in MongoDB + + + 2014-2017 + + + Pivotal, Inc. + https://www.spring.io + + + + + rwinch + Rob Winch + rwinch(at)pivotal.io + Pivotal Software, Inc. + + Creator + + -6 + + + gturnquist + Greg Turnquist + gturnquist(at)pivotal.io + Pivotal Software, Inc. + + Project Lead + + -6 + + + + + + Apache License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0 + + Copyright 2011 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. + + + + + + UTF-8 + 1.50.5 + 1.3 + 2.9.0.pr3 + 4.12 + 2.7.22 + 5.0.0.RC1 + Kay-M3 + 2.0.0.BUILD-SNAPSHOT + 1.8 + 3.6.2 + 5.0.0.M1 + + + + + + spring5-next + + Kay-BUILD-SNAPSHOT + 5.0.0.BUILD-SNAPSHOT + + + + spring-libs-snapshot + http://repo.spring.io/libs-snapshot + + + + + + + + + ci + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.10.4 + + + + jar + + package + + + + + + + + + + + + + + distribute + + + ${project.build.directory}/shared-resources + true + true + ${basedir} + + + + + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + + aggregate-javadoc + + aggregate + + package + + + + + + org.asciidoctor + asciidoctor-maven-plugin + 1.5.3 + + + org.asciidoctor + asciidoctorj-pdf + 1.5.0-alpha.11 + + + org.asciidoctor + asciidoctorj-epub3 + 1.5.0-alpha.6 + + + + + + html + generate-resources + + process-asciidoc + + + html5 + ${project.build.directory}/site/reference/html + false + prettify + + true + font + true + spring.css + + + + + + pdf + generate-resources + + process-asciidoc + + + pdf + coderay + + + + + + + ${project.root}/src/main/asciidoc + index.adoc + book + + ${project.version} + ${project.name} + ${project.version} + true + 3 + true + ${project.basedir} + + + + + + + + + + + + + + + org.springframework.data + spring-data-releasetrain + ${spring-data.version} + pom + import + + + + org.springframework + spring-framework-bom + ${spring.version} + pom + import + + + + org.springframework.security + spring-security-bom + ${spring-security.version} + pom + import + + + + + + + + org.springframework.session + spring-session + ${spring-session.version} + + + + org.springframework.data + spring-data-mongodb + + + + com.fasterxml.jackson.core + jackson-databind + ${jackson.version} + + + + + + org.springframework.security + spring-security-core + + + + org.springframework + spring-web + + + + de.flapdoodle.embed + de.flapdoodle.embed.mongo + ${flapdoodle.version} + test + + + + org.assertj + assertj-core + ${assertj.version} + test + + + + org.hamcrest + hamcrest-library + ${hamcrest.version} + test + + + + junit + junit + ${junit.version} + test + + + + org.springframework + spring-test + test + + + + org.mockito + mockito-core + ${mockito.version} + test + + + + javax.servlet + javax.servlet-api + 3.1.0 + test + + + + + + + + + org.apache.maven.wagon + wagon-ssh + 2.5 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.3 + + ${source.level} + ${source.level} + + + + + org.apache.maven.plugins + maven-jar-plugin + 2.6 + + true + + + + + org.apache.maven.plugins + maven-source-plugin + 2.4 + + + attach-sources + + jar + + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.10.3 + + true +
${project.name}
+ ${source.level} + true + -Xdoclint:none + + http://static.springframework.org/spring/docs/4.1.x/javadoc-api + http://docs.oracle.com/javase/6/docs/api + +
+
+ + + org.apache.maven.plugins + maven-deploy-plugin + 2.8.2 + + true + + + +
+
+ + + + spring-plugins-release + https://repo.spring.io/plugins-release + + + + + + spring-libs-snapshot + https://repo.spring.io/libs-snapshot + + + + + https://github.com/spring-projects/spring-session-mongodb + scm:git:git://github.com/spring-projects/spring-session-mongodb.git + scm:git:ssh://git@github.com:spring-projects/spring-session-mongodb.git + + +
\ No newline at end of file diff --git a/samples/boot/findbyusername/README.adoc b/samples/boot/findbyusername/README.adoc deleted file mode 100644 index 92307b7..0000000 --- a/samples/boot/findbyusername/README.adoc +++ /dev/null @@ -1,4 +0,0 @@ -Demonstrates using Spring Session to lookup a user's session by the username. -The sample provides a hook to add the current username to the session (required for finding the user) by providing a custom implementation of Spring Security's `AuthenticationSuccessHandler`. - -NOTE: This product includes GeoLite2 data created by MaxMind, available from http://www.maxmind.com \ No newline at end of file diff --git a/samples/boot/findbyusername/spring-session-sample-boot-findbyusername.gradle b/samples/boot/findbyusername/spring-session-sample-boot-findbyusername.gradle deleted file mode 100644 index f765848..0000000 --- a/samples/boot/findbyusername/spring-session-sample-boot-findbyusername.gradle +++ /dev/null @@ -1,31 +0,0 @@ -apply plugin: 'io.spring.convention.spring-sample-boot' - -dependencies { - compile project(':spring-session-data-redis') - compile "org.springframework.boot:spring-boot-starter-security" - compile "org.springframework.boot:spring-boot-starter-thymeleaf" - compile "org.springframework.boot:spring-boot-starter-web" - compile "nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect" - compile "org.webjars:bootstrap" - compile "org.webjars:html5shiv" - compile "org.webjars:webjars-locator" - compile "com.maxmind.geoip2:geoip2" - compile "org.apache.httpcomponents:httpclient" - - testCompile "org.springframework.boot:spring-boot-starter-test" - testCompile "org.assertj:assertj-core" - - integrationTestCompile seleniumDependencies - -} - -integrationTest { - doFirst { - systemProperties['spring.session.redis.namespace'] = project.name - } -} -integrationTest { - doFirst { - systemProperties['spring.session.redis.namespace'] = project.name - } -} \ No newline at end of file diff --git a/samples/boot/findbyusername/src/integration-test/java/sample/FindByUsernameTests.java b/samples/boot/findbyusername/src/integration-test/java/sample/FindByUsernameTests.java deleted file mode 100644 index 12ed00b..0000000 --- a/samples/boot/findbyusername/src/integration-test/java/sample/FindByUsernameTests.java +++ /dev/null @@ -1,75 +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.junit.runner.RunWith; -import org.openqa.selenium.WebDriver; -import sample.pages.HomePage; -import sample.pages.LoginPage; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.htmlunit.webdriver.MockMvcHtmlUnitDriverBuilder; - -/** - * @author Eddú Meléndez - * @author Rob Winch - */ -@RunWith(SpringRunner.class) -@AutoConfigureMockMvc -@SpringBootTest(webEnvironment = WebEnvironment.MOCK) -public class FindByUsernameTests { - - @Autowired - private MockMvc mockMvc; - - private WebDriver driver; - - @Before - public void setup() { - this.driver = MockMvcHtmlUnitDriverBuilder.mockMvcSetup(this.mockMvc).build(); - } - - @After - public void tearDown() { - this.driver.quit(); - } - - @Test - public void home() { - LoginPage login = HomePage.go(this.driver); - login.assertAt(); - } - - @Test - public void login() { - LoginPage login = HomePage.go(this.driver); - HomePage home = login.form().login(HomePage.class); - home.assertAt(); - home.containCookie("SESSION"); - home.doesNotContainCookie("JSESSIONID"); - home.terminateButtonDisabled(); - } - -} diff --git a/samples/boot/findbyusername/src/integration-test/java/sample/pages/BasePage.java b/samples/boot/findbyusername/src/integration-test/java/sample/pages/BasePage.java deleted file mode 100644 index 763c078..0000000 --- a/samples/boot/findbyusername/src/integration-test/java/sample/pages/BasePage.java +++ /dev/null @@ -1,41 +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; - -/** - * @author Eddú Meléndez - */ -public 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"; - driver.get(baseUrl + get); - } - -} diff --git a/samples/boot/findbyusername/src/integration-test/java/sample/pages/HomePage.java b/samples/boot/findbyusername/src/integration-test/java/sample/pages/HomePage.java deleted file mode 100644 index ea4d309..0000000 --- a/samples/boot/findbyusername/src/integration-test/java/sample/pages/HomePage.java +++ /dev/null @@ -1,79 +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 java.util.Base64; -import java.util.Set; - -import org.openqa.selenium.By; -import org.openqa.selenium.Cookie; -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 Eddú Meléndez - * @author Rob Winch - */ -public class HomePage extends BasePage { - @FindBy(css = "input[type=\"submit\"]") - WebElement logout; - - public HomePage(WebDriver driver) { - super(driver); - } - - public void assertAt() { - assertThat(getDriver().getTitle()) - .isEqualTo("Spring Session Sample - Secured Content"); - } - - public void containCookie(String cookieName) { - Set cookies = getDriver().manage().getCookies(); - assertThat(cookies).extracting("name").contains(cookieName); - } - - public void doesNotContainCookie(String cookieName) { - Set cookies = getDriver().manage().getCookies(); - assertThat(cookies).extracting("name").doesNotContain(cookieName); - } - - public void terminateButtonDisabled() { - Set cookies = getDriver().manage().getCookies(); - String cookieValue = null; - for (Cookie cookie : cookies) { - if ("SESSION".equals(cookie.getName())) { - cookieValue = new String(Base64.getDecoder().decode(cookie.getValue())); - } - } - WebElement element = getDriver().findElement(By.id("terminate-" + cookieValue)); - assertThat(element.isEnabled()).isFalse(); - } - - public HomePage logout() { - this.logout.click(); - return PageFactory.initElements(getDriver(), HomePage.class); - } - - public static LoginPage go(WebDriver driver) { - get(driver, "/"); - return PageFactory.initElements(driver, LoginPage.class); - } -} diff --git a/samples/boot/findbyusername/src/integration-test/java/sample/pages/LoginPage.java b/samples/boot/findbyusername/src/integration-test/java/sample/pages/LoginPage.java deleted file mode 100644 index 16cf562..0000000 --- a/samples/boot/findbyusername/src/integration-test/java/sample/pages/LoginPage.java +++ /dev/null @@ -1,68 +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.SearchContext; -import org.openqa.selenium.WebDriver; -import org.openqa.selenium.WebElement; -import org.openqa.selenium.support.FindBy; -import org.openqa.selenium.support.PageFactory; -import org.openqa.selenium.support.pagefactory.DefaultElementLocatorFactory; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Eddú Meléndez - * @author Rob Winch - */ -public class LoginPage extends BasePage { - - public LoginPage(WebDriver driver) { - super(driver); - } - - public void assertAt() { - assertThat(getDriver().getTitle()).isEqualTo("Spring Session Sample - Log In"); - } - - public Form form() { - return new Form(getDriver()); - } - - public class Form { - - @FindBy(name = "username") - private WebElement username; - - @FindBy(name = "password") - private WebElement password; - - @FindBy(tagName = "button") - private WebElement button; - - public Form(SearchContext context) { - PageFactory.initElements(new DefaultElementLocatorFactory(context), this); - } - - public T login(Class page) { - this.username.sendKeys("user"); - this.password.sendKeys("password"); - this.button.click(); - return PageFactory.initElements(getDriver(), page); - } - } -} diff --git a/samples/boot/findbyusername/src/main/java/sample/FindByUsernameApplication.java b/samples/boot/findbyusername/src/main/java/sample/FindByUsernameApplication.java deleted file mode 100644 index 6bd1281..0000000 --- a/samples/boot/findbyusername/src/main/java/sample/FindByUsernameApplication.java +++ /dev/null @@ -1,31 +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.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -/** - * @author Rob Winch - */ -@SpringBootApplication -public class FindByUsernameApplication { - - public static void main(String[] args) { - SpringApplication.run(FindByUsernameApplication.class, args); - } -} diff --git a/samples/boot/findbyusername/src/main/java/sample/config/GeoConfig.java b/samples/boot/findbyusername/src/main/java/sample/config/GeoConfig.java deleted file mode 100644 index c5b57b3..0000000 --- a/samples/boot/findbyusername/src/main/java/sample/config/GeoConfig.java +++ /dev/null @@ -1,42 +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.config; - -import java.io.InputStream; - -import com.maxmind.geoip2.DatabaseReader; - -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -/** - * - * @author Rob Winch - * - */ -@Configuration -public class GeoConfig { - - @Bean - public DatabaseReader geoDatabaseReader( - @Value("classpath:GeoLite2-City.mmdb") InputStream geoInputStream) - throws Exception { - return new DatabaseReader.Builder(geoInputStream).build(); - } - -} diff --git a/samples/boot/findbyusername/src/main/java/sample/config/HttpSessionConfig.java b/samples/boot/findbyusername/src/main/java/sample/config/HttpSessionConfig.java deleted file mode 100644 index 76d431e..0000000 --- a/samples/boot/findbyusername/src/main/java/sample/config/HttpSessionConfig.java +++ /dev/null @@ -1,30 +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.config; - -import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession; - -/** - * - * @author Rob Winch - * - */ -// tag::class[] -@EnableRedisHttpSession // <1> -public class HttpSessionConfig { -} -// end::class[] diff --git a/samples/boot/findbyusername/src/main/java/sample/config/SecurityConfig.java b/samples/boot/findbyusername/src/main/java/sample/config/SecurityConfig.java deleted file mode 100644 index 575cfc7..0000000 --- a/samples/boot/findbyusername/src/main/java/sample/config/SecurityConfig.java +++ /dev/null @@ -1,44 +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.config; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; - -/** - * @author Rob Winch - */ -@EnableWebSecurity -public class SecurityConfig extends WebSecurityConfigurerAdapter { - - // tag::config[] - @Override - protected void configure(HttpSecurity http) throws Exception { - http.formLogin().loginPage("/login").permitAll().and().authorizeRequests() - .antMatchers("/resources/**", "/webjars/**").permitAll().anyRequest().authenticated() - .and().logout().permitAll(); - } - // end::config[] - - @Autowired - public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { - auth.inMemoryAuthentication().withUser("user").password("password").roles("USER"); - } -} diff --git a/samples/boot/findbyusername/src/main/java/sample/mvc/IndexController.java b/samples/boot/findbyusername/src/main/java/sample/mvc/IndexController.java deleted file mode 100644 index 9327f3d..0000000 --- a/samples/boot/findbyusername/src/main/java/sample/mvc/IndexController.java +++ /dev/null @@ -1,68 +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.mvc; - -import java.security.Principal; -import java.util.Collection; -import java.util.Set; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.session.ExpiringSession; -import org.springframework.session.FindByIndexNameSessionRepository; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; - -/** - * Controller for sending the user to the login view. - * - * @author Rob Winch - * - */ -@Controller -public class IndexController { - // tag::findbyusername[] - @Autowired - FindByIndexNameSessionRepository sessions; - - @RequestMapping("/") - public String index(Principal principal, Model model) { - Collection usersSessions = this.sessions - .findByIndexNameAndIndexValue( - FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, - principal.getName()) - .values(); - model.addAttribute("sessions", usersSessions); - return "index"; - } - // end::findbyusername[] - - @RequestMapping(value = "/sessions/{sessionIdToDelete}", method = RequestMethod.DELETE) - public String removeSession(Principal principal, - @PathVariable String sessionIdToDelete) { - Set usersSessionIds = this.sessions.findByIndexNameAndIndexValue( - FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, - principal.getName()).keySet(); - if (usersSessionIds.contains(sessionIdToDelete)) { - this.sessions.delete(sessionIdToDelete); - } - - return "redirect:/"; - } -} diff --git a/samples/boot/findbyusername/src/main/java/sample/mvc/LoginController.java b/samples/boot/findbyusername/src/main/java/sample/mvc/LoginController.java deleted file mode 100644 index 7403b02..0000000 --- a/samples/boot/findbyusername/src/main/java/sample/mvc/LoginController.java +++ /dev/null @@ -1,34 +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.mvc; - -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.RequestMapping; - -/** - * Returns view for log in page - * - * @author Rob Winch - */ -@Controller -public class LoginController { - - @RequestMapping("/login") - public String login() { - return "login"; - } -} diff --git a/samples/boot/findbyusername/src/main/java/sample/session/SessionDetails.java b/samples/boot/findbyusername/src/main/java/sample/session/SessionDetails.java deleted file mode 100644 index 03be008..0000000 --- a/samples/boot/findbyusername/src/main/java/sample/session/SessionDetails.java +++ /dev/null @@ -1,51 +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.session; - -import java.io.Serializable; - -/** - * An example of how users can provide details about their session. - * - * @author Rob Winch - * @see SessionDetailsFilter - */ -// tag::class[] -public class SessionDetails implements Serializable { - private String location; - - private String accessType; - - public String getLocation() { - return this.location; - } - - public void setLocation(String location) { - this.location = location; - } - - public String getAccessType() { - return this.accessType; - } - - public void setAccessType(String accessType) { - this.accessType = accessType; - } - - private static final long serialVersionUID = 8850489178248613501L; -} -// end::class[] diff --git a/samples/boot/findbyusername/src/main/java/sample/session/SessionDetailsFilter.java b/samples/boot/findbyusername/src/main/java/sample/session/SessionDetailsFilter.java deleted file mode 100644 index e3d796a..0000000 --- a/samples/boot/findbyusername/src/main/java/sample/session/SessionDetailsFilter.java +++ /dev/null @@ -1,111 +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.session; - -import java.io.IOException; -import java.net.InetAddress; - -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; - -import com.maxmind.geoip2.DatabaseReader; -import com.maxmind.geoip2.model.CityResponse; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.core.Ordered; -import org.springframework.core.annotation.Order; -import org.springframework.stereotype.Component; -import org.springframework.web.filter.OncePerRequestFilter; - -/** - * Inserts the session details into the session for every request. Some users may prefer - * to insert session details only after authentication. This is fine, but it may be - * valuable to the most up to date information so that if someone stole the user's session - * id it can be observed. - * - * @author Rob Winch - * - */ -// tag::class[] -@Component -@Order(Ordered.HIGHEST_PRECEDENCE + 101) -public class SessionDetailsFilter extends OncePerRequestFilter { - static final String UNKNOWN = "Unknown"; - - private DatabaseReader reader; - - @Autowired - public SessionDetailsFilter(DatabaseReader reader) { - this.reader = reader; - } - - // tag::dofilterinternal[] - public void doFilterInternal(HttpServletRequest request, HttpServletResponse response, - FilterChain chain) throws IOException, ServletException { - chain.doFilter(request, response); - - HttpSession session = request.getSession(false); - if (session != null) { - String remoteAddr = getRemoteAddress(request); - String geoLocation = getGeoLocation(remoteAddr); - - SessionDetails details = new SessionDetails(); - details.setAccessType(request.getHeader("User-Agent")); - details.setLocation(remoteAddr + " " + geoLocation); - - session.setAttribute("SESSION_DETAILS", details); - } - } - // end::dofilterinternal[] - - String getGeoLocation(String remoteAddr) { - try { - CityResponse city = this.reader.city(InetAddress.getByName(remoteAddr)); - String cityName = city.getCity().getName(); - String countryName = city.getCountry().getName(); - if (cityName == null && countryName == null) { - return null; - } - else if (cityName == null) { - return countryName; - } - else if (countryName == null) { - return cityName; - } - return cityName + ", " + countryName; - } - catch (Exception e) { - return UNKNOWN; - - } - } - - private String getRemoteAddress(HttpServletRequest request) { - String remoteAddr = request.getHeader("X-FORWARDED-FOR"); - if (remoteAddr == null) { - remoteAddr = request.getRemoteAddr(); - } - else if (remoteAddr.contains(",")) { - remoteAddr = remoteAddr.split(",")[0]; - } - return remoteAddr; - } -} -// end::class[] diff --git a/samples/boot/findbyusername/src/main/resources/GeoLite2-City.mmdb b/samples/boot/findbyusername/src/main/resources/GeoLite2-City.mmdb deleted file mode 100644 index 48755ed..0000000 Binary files a/samples/boot/findbyusername/src/main/resources/GeoLite2-City.mmdb and /dev/null differ diff --git a/samples/boot/findbyusername/src/main/resources/application.properties b/samples/boot/findbyusername/src/main/resources/application.properties deleted file mode 100644 index f0baad3..0000000 --- a/samples/boot/findbyusername/src/main/resources/application.properties +++ /dev/null @@ -1,2 +0,0 @@ -spring.thymeleaf.cache=false -spring.template.cache=false diff --git a/samples/boot/findbyusername/src/main/resources/static/resources/img/favicon.ico b/samples/boot/findbyusername/src/main/resources/static/resources/img/favicon.ico deleted file mode 100644 index bfb9974..0000000 Binary files a/samples/boot/findbyusername/src/main/resources/static/resources/img/favicon.ico and /dev/null differ diff --git a/samples/boot/findbyusername/src/main/resources/static/resources/img/logo.png b/samples/boot/findbyusername/src/main/resources/static/resources/img/logo.png deleted file mode 100644 index 3932308..0000000 Binary files a/samples/boot/findbyusername/src/main/resources/static/resources/img/logo.png and /dev/null differ diff --git a/samples/boot/findbyusername/src/main/resources/templates/index.html b/samples/boot/findbyusername/src/main/resources/templates/index.html deleted file mode 100644 index 8681b4a..0000000 --- a/samples/boot/findbyusername/src/main/resources/templates/index.html +++ /dev/null @@ -1,36 +0,0 @@ - - - Secured Content - - -
-

Secured Page

-

This page is secured using Spring Boot, Spring Session, and Spring Security.

- -

Your current session id is

- - - - - - - - - - - - - - - - - - -
Id SuffixLocationCreatedLast UpdatedInformationTerminate
-
- -
-
-
- - diff --git a/samples/boot/findbyusername/src/main/resources/templates/layout.html b/samples/boot/findbyusername/src/main/resources/templates/layout.html deleted file mode 100644 index 40863f6..0000000 --- a/samples/boot/findbyusername/src/main/resources/templates/layout.html +++ /dev/null @@ -1,122 +0,0 @@ - - - - Spring Session Sample - - - - - - - - - - - -
- - -
-
- Some Success message -
-
- Fake content -
-
- -
-
- - - - diff --git a/samples/boot/findbyusername/src/main/resources/templates/login.html b/samples/boot/findbyusername/src/main/resources/templates/login.html deleted file mode 100644 index 2ab4d08..0000000 --- a/samples/boot/findbyusername/src/main/resources/templates/login.html +++ /dev/null @@ -1,47 +0,0 @@ - - -Log In - - -
-
-
- Please Login -
Invalid - username and password.
-
You - have been logged out.
- - -
- -
-
-
- -
-

The intention is to demo a way to terminate a user's active - session without access to the device. Consider the following

-
    -
  • User goes to library and authenticates to the application
  • -
  • User goes home and realizes they forgot to log out
  • -
  • User can log in and terminate the session from the library - using clues like the location, created time, last accessed time, - etc.
  • -
- -

To emulate the workflow:

- -
    -
  • Sign in with the username "user" and password "password"
  • -
  • Sign in again using an incognito window
  • -
  • Terminate your original session
  • -
  • Refresh the original window and see you are logged out
  • -
-
-
- - \ No newline at end of file diff --git a/samples/boot/findbyusername/src/test/java/sample/session/SessionDetailsFilterTests.java b/samples/boot/findbyusername/src/test/java/sample/session/SessionDetailsFilterTests.java deleted file mode 100644 index eca2bba..0000000 --- a/samples/boot/findbyusername/src/test/java/sample/session/SessionDetailsFilterTests.java +++ /dev/null @@ -1,66 +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.session; - -import com.maxmind.geoip2.DatabaseReader; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -import sample.config.GeoConfig; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Rob Winch - * - */ -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(classes = GeoConfig.class) -public class SessionDetailsFilterTests { - @Autowired - DatabaseReader reader; - - SessionDetailsFilter filter; - - @Before - public void setup() { - this.filter = new SessionDetailsFilter(this.reader); - } - - @Test - public void getGeoLocationHanldesInvalidIp() { - assertThat(this.filter.getGeoLocation("a")) - .isEqualTo(SessionDetailsFilter.UNKNOWN); - } - - @Test - public void getGeoLocationNullCity() { - assertThat(this.filter.getGeoLocation("22.231.113.64")) - .isEqualTo("United States"); - } - - @Test - public void getGeoLocationBoth() { - assertThat(this.filter.getGeoLocation("184.154.83.119")) - .isEqualTo("Chicago, United States"); - } -} diff --git a/samples/boot/jdbc/README.adoc b/samples/boot/jdbc/README.adoc deleted file mode 100644 index d7203b5..0000000 --- a/samples/boot/jdbc/README.adoc +++ /dev/null @@ -1 +0,0 @@ -Demonstrates using Spring Session with Spring Boot and Spring Security. You can log in with the username "user" and the password "password". \ No newline at end of file diff --git a/samples/boot/jdbc/spring-session-sample-boot-jdbc.gradle b/samples/boot/jdbc/spring-session-sample-boot-jdbc.gradle deleted file mode 100644 index e635c1a..0000000 --- a/samples/boot/jdbc/spring-session-sample-boot-jdbc.gradle +++ /dev/null @@ -1,20 +0,0 @@ -apply plugin: 'io.spring.convention.spring-sample-boot' - -dependencies { - compile project(':spring-session-jdbc') - compile "org.springframework.boot:spring-boot-starter-jdbc" - compile"org.springframework.boot:spring-boot-starter-web" - compile"org.springframework.boot:spring-boot-starter-security" - compile"org.springframework.boot:spring-boot-starter-thymeleaf" - compile"nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect" - compile"org.webjars:bootstrap" - compile"org.webjars:html5shiv" - compile"org.webjars:webjars-locator" - compile"com.h2database:h2" - - testCompile "org.springframework.boot:spring-boot-starter-test" - testCompile "org.assertj:assertj-core" - - integrationTestCompile seleniumDependencies - -} \ No newline at end of file diff --git a/samples/boot/jdbc/src/integration-test/java/sample/BootTests.java b/samples/boot/jdbc/src/integration-test/java/sample/BootTests.java deleted file mode 100644 index 8ef19ba..0000000 --- a/samples/boot/jdbc/src/integration-test/java/sample/BootTests.java +++ /dev/null @@ -1,82 +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.junit.runner.RunWith; -import org.openqa.selenium.WebDriver; -import sample.pages.HomePage; -import sample.pages.LoginPage; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.htmlunit.webdriver.MockMvcHtmlUnitDriverBuilder; - -/** - * @author Eddú Meléndez - */ -@RunWith(SpringRunner.class) -@AutoConfigureMockMvc -@SpringBootTest(webEnvironment = WebEnvironment.MOCK) -public class BootTests { - - @Autowired - private MockMvc mockMvc; - - private WebDriver driver; - - @Before - public void setup() { - this.driver = MockMvcHtmlUnitDriverBuilder.mockMvcSetup(this.mockMvc).build(); - } - - @After - public void tearDown() { - this.driver.quit(); - } - - @Test - public void home() { - LoginPage login = HomePage.go(this.driver); - login.assertAt(); - HomePage home = login.form().login(HomePage.class); - home.assertAt(); - } - - @Test - public void login() { - LoginPage login = HomePage.go(this.driver); - HomePage home = login.form().login(HomePage.class); - home.containCookie("SESSION"); - home.doesNotContainCookie("JSESSIONID"); - } - - @Test - public void logout() { - LoginPage login = HomePage.go(this.driver); - HomePage home = login.form().login(HomePage.class); - login = home.logout(); - login.assertAt(); - } - -} diff --git a/samples/boot/jdbc/src/integration-test/java/sample/pages/BasePage.java b/samples/boot/jdbc/src/integration-test/java/sample/pages/BasePage.java deleted file mode 100644 index 763c078..0000000 --- a/samples/boot/jdbc/src/integration-test/java/sample/pages/BasePage.java +++ /dev/null @@ -1,41 +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; - -/** - * @author Eddú Meléndez - */ -public 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"; - driver.get(baseUrl + get); - } - -} diff --git a/samples/boot/jdbc/src/integration-test/java/sample/pages/HomePage.java b/samples/boot/jdbc/src/integration-test/java/sample/pages/HomePage.java deleted file mode 100644 index 5169002..0000000 --- a/samples/boot/jdbc/src/integration-test/java/sample/pages/HomePage.java +++ /dev/null @@ -1,63 +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 java.util.Set; - -import org.openqa.selenium.By; -import org.openqa.selenium.Cookie; -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 Eddú Meléndez - */ -public class HomePage extends BasePage { - - public HomePage(WebDriver driver) { - super(driver); - } - - public static LoginPage go(WebDriver driver) { - get(driver, "/"); - return PageFactory.initElements(driver, LoginPage.class); - } - - public void assertAt() { - assertThat(getDriver().getTitle()).isEqualTo("Spring Session Sample - Secured Content"); - } - - public void containCookie(String cookieName) { - Set cookies = getDriver().manage().getCookies(); - assertThat(cookies).extracting("name").contains(cookieName); - } - - public void doesNotContainCookie(String cookieName) { - Set cookies = getDriver().manage().getCookies(); - assertThat(cookies).extracting("name").doesNotContain(cookieName); - } - - public LoginPage logout() { - WebElement logout = getDriver().findElement(By.cssSelector("input[type=\"submit\"]")); - logout.click(); - return PageFactory.initElements(getDriver(), LoginPage.class); - } - -} diff --git a/samples/boot/jdbc/src/integration-test/java/sample/pages/LoginPage.java b/samples/boot/jdbc/src/integration-test/java/sample/pages/LoginPage.java deleted file mode 100644 index e3e89f3..0000000 --- a/samples/boot/jdbc/src/integration-test/java/sample/pages/LoginPage.java +++ /dev/null @@ -1,69 +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.SearchContext; -import org.openqa.selenium.WebDriver; -import org.openqa.selenium.WebElement; -import org.openqa.selenium.support.FindBy; -import org.openqa.selenium.support.PageFactory; -import org.openqa.selenium.support.pagefactory.DefaultElementLocatorFactory; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Eddú Meléndez - * @author Rob Winch - */ -public class LoginPage extends BasePage { - - public LoginPage(WebDriver driver) { - super(driver); - } - - public void assertAt() { - assertThat(getDriver().getTitle()).isEqualTo("Login Page"); - } - - public Form form() { - return new Form(getDriver()); - } - - public class Form { - - @FindBy(name = "username") - private WebElement username; - - @FindBy(name = "password") - private WebElement password; - - @FindBy(name = "submit") - private WebElement button; - - public Form(SearchContext context) { - PageFactory.initElements(new DefaultElementLocatorFactory(context), this); - } - - public T login(Class page) { - this.username.sendKeys("user"); - this.password.sendKeys("password"); - this.button.click(); - return PageFactory.initElements(getDriver(), page); - } - } - -} diff --git a/samples/boot/jdbc/src/main/java/sample/Application.java b/samples/boot/jdbc/src/main/java/sample/Application.java deleted file mode 100644 index 02627e7..0000000 --- a/samples/boot/jdbc/src/main/java/sample/Application.java +++ /dev/null @@ -1,31 +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 org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -/** - * @author Rob Winch - */ -@SpringBootApplication -public class Application { - - public static void main(String[] args) { - SpringApplication.run(Application.class, args); - } -} diff --git a/samples/boot/jdbc/src/main/java/sample/config/HttpSessionConfig.java b/samples/boot/jdbc/src/main/java/sample/config/HttpSessionConfig.java deleted file mode 100644 index 946ded9..0000000 --- a/samples/boot/jdbc/src/main/java/sample/config/HttpSessionConfig.java +++ /dev/null @@ -1,25 +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.config; - -import org.springframework.session.jdbc.config.annotation.web.http.EnableJdbcHttpSession; - -// tag::class[] -@EnableJdbcHttpSession // <1> -public class HttpSessionConfig { -} -// end::class[] diff --git a/samples/boot/jdbc/src/main/java/sample/config/SecurityConfig.java b/samples/boot/jdbc/src/main/java/sample/config/SecurityConfig.java deleted file mode 100644 index 602ac1a..0000000 --- a/samples/boot/jdbc/src/main/java/sample/config/SecurityConfig.java +++ /dev/null @@ -1,51 +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.config; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; -import org.springframework.security.config.annotation.web.builders.WebSecurity; -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; - -/** - * @author Rob Winch - * @author Vedran Pavic - */ -@EnableWebSecurity -public class SecurityConfig extends WebSecurityConfigurerAdapter { - - // @formatter:off - @Autowired - public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { - auth - .inMemoryAuthentication() - .withUser("user") - .password("password") - .roles("USER"); - } - // @formatter:on - - // @formatter:off - @Override - public void configure(WebSecurity web) throws Exception { - web - .ignoring().antMatchers("/h2-console/**"); - } - // @formatter:on - -} diff --git a/samples/boot/jdbc/src/main/java/sample/mvc/IndexController.java b/samples/boot/jdbc/src/main/java/sample/mvc/IndexController.java deleted file mode 100644 index 8c94fb3..0000000 --- a/samples/boot/jdbc/src/main/java/sample/mvc/IndexController.java +++ /dev/null @@ -1,34 +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.mvc; - -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.RequestMapping; - -/** - * Controller for sending the user to the login view. - * - * @author Rob Winch - * - */ -@Controller -public class IndexController { - @RequestMapping("/") - public String index() { - return "index"; - } -} diff --git a/samples/boot/jdbc/src/main/resources/application.properties b/samples/boot/jdbc/src/main/resources/application.properties deleted file mode 100644 index 7e0549f..0000000 --- a/samples/boot/jdbc/src/main/resources/application.properties +++ /dev/null @@ -1,4 +0,0 @@ -spring.thymeleaf.cache=false -spring.template.cache=false -spring.datasource.schema=classpath:org/springframework/session/jdbc/schema-h2.sql -spring.h2.console.enabled=true diff --git a/samples/boot/jdbc/src/main/resources/static/resources/img/favicon.ico b/samples/boot/jdbc/src/main/resources/static/resources/img/favicon.ico deleted file mode 100644 index bfb9974..0000000 Binary files a/samples/boot/jdbc/src/main/resources/static/resources/img/favicon.ico and /dev/null differ diff --git a/samples/boot/jdbc/src/main/resources/static/resources/img/logo.png b/samples/boot/jdbc/src/main/resources/static/resources/img/logo.png deleted file mode 100644 index 3932308..0000000 Binary files a/samples/boot/jdbc/src/main/resources/static/resources/img/logo.png and /dev/null differ diff --git a/samples/boot/jdbc/src/main/resources/templates/index.html b/samples/boot/jdbc/src/main/resources/templates/index.html deleted file mode 100644 index 1e2703e..0000000 --- a/samples/boot/jdbc/src/main/resources/templates/index.html +++ /dev/null @@ -1,11 +0,0 @@ - - - Secured Content - - -
-

Secured Page

-

This page is secured using Spring Boot, Spring Session, and Spring Security.

-
- - diff --git a/samples/boot/jdbc/src/main/resources/templates/layout.html b/samples/boot/jdbc/src/main/resources/templates/layout.html deleted file mode 100644 index 7a66980..0000000 --- a/samples/boot/jdbc/src/main/resources/templates/layout.html +++ /dev/null @@ -1,122 +0,0 @@ - - - - Spring Session Sample - - - - - - - - - - - -
- - -
-
- Some Success message -
-
- Fake content -
-
- -
-
- - - - diff --git a/samples/boot/redis-json/spring-session-sample-boot-redis-json.gradle b/samples/boot/redis-json/spring-session-sample-boot-redis-json.gradle deleted file mode 100644 index b67773e..0000000 --- a/samples/boot/redis-json/spring-session-sample-boot-redis-json.gradle +++ /dev/null @@ -1,19 +0,0 @@ -apply plugin: 'io.spring.convention.spring-sample-boot' - -dependencies { - compile project(':spring-session') - compile"org.springframework.data:spring-data-redis" - compile"io.lettuce:lettuce-core" - compile"org.springframework.boot:spring-boot-starter-web" - compile"org.springframework.boot:spring-boot-starter-thymeleaf" - compile"org.springframework.boot:spring-boot-starter-security" - compile"nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect" - compile"org.apache.httpcomponents:httpclient" - - testCompile "org.springframework.boot:spring-boot-starter-test" - testCompile"org.assertj:assertj-core" - testCompile "org.skyscreamer:jsonassert" - - integrationTestCompile seleniumDependencies - -} \ No newline at end of file diff --git a/samples/boot/redis-json/src/integration-test/java/sample/HttpRedisJsonTest.java b/samples/boot/redis-json/src/integration-test/java/sample/HttpRedisJsonTest.java deleted file mode 100644 index d777fc3..0000000 --- a/samples/boot/redis-json/src/integration-test/java/sample/HttpRedisJsonTest.java +++ /dev/null @@ -1,99 +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.util.List; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.openqa.selenium.WebDriver; -import sample.pages.HomePage; -import sample.pages.HomePage.Attribute; -import sample.pages.LoginPage; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.htmlunit.webdriver.MockMvcHtmlUnitDriverBuilder; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Eddú Meléndez - */ -@RunWith(SpringRunner.class) -@SpringBootTest(webEnvironment = WebEnvironment.MOCK) -@AutoConfigureMockMvc -public class HttpRedisJsonTest { - - @Autowired - private MockMvc mockMvc; - - private WebDriver driver; - - @Before - public void setup() { - this.driver = MockMvcHtmlUnitDriverBuilder.mockMvcSetup(this.mockMvc).build(); - } - - @After - public void tearDown() { - this.driver.quit(); - } - - @Test - public void goLoginRedirectToLogin() { - LoginPage login = HomePage.go(this.driver, LoginPage.class); - login.assertAt(); - } - - @Test - public void goHomeRedirectLoginPage() { - LoginPage login = HomePage.go(this.driver, LoginPage.class); - login.assertAt(); - } - - @Test - public void login() { - LoginPage login = HomePage.go(this.driver, LoginPage.class); - HomePage home = login.form().login(HomePage.class); - home.containCookie("SESSION"); - home.doesNotContainCookie("JSESSIONID"); - } - - @Test - public void createAttribute() { - LoginPage login = HomePage.go(this.driver, LoginPage.class); - HomePage home = login.form().login(HomePage.class); - // @formatter:off - home = home.form() - .attributeName("Demo Key") - .attributeValue("Demo Value") - .submit(HomePage.class); - // @formatter:on - - List attributes = home.attributes(); - assertThat(attributes).extracting("attributeName").contains("Demo Key"); - assertThat(attributes).extracting("attributeValue").contains("Demo Value"); - } - -} diff --git a/samples/boot/redis-json/src/integration-test/java/sample/RedisSerializerTest.java b/samples/boot/redis-json/src/integration-test/java/sample/RedisSerializerTest.java deleted file mode 100644 index e44c472..0000000 --- a/samples/boot/redis-json/src/integration-test/java/sample/RedisSerializerTest.java +++ /dev/null @@ -1,46 +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 org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; -import org.springframework.test.context.junit4.SpringRunner; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author jitendra on 8/3/16. - */ -@RunWith(SpringRunner.class) -@SpringBootTest -public class RedisSerializerTest { - - @Autowired - RedisTemplate sessionRedisTemplate; - - @Test - public void testRedisTemplate() { - assertThat(this.sessionRedisTemplate).isNotNull(); - assertThat(this.sessionRedisTemplate.getDefaultSerializer()).isNotNull(); - assertThat(this.sessionRedisTemplate.getDefaultSerializer()) - .isInstanceOf(GenericJackson2JsonRedisSerializer.class); - } -} diff --git a/samples/boot/redis-json/src/integration-test/java/sample/pages/BasePage.java b/samples/boot/redis-json/src/integration-test/java/sample/pages/BasePage.java deleted file mode 100644 index 763c078..0000000 --- a/samples/boot/redis-json/src/integration-test/java/sample/pages/BasePage.java +++ /dev/null @@ -1,41 +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; - -/** - * @author Eddú Meléndez - */ -public 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"; - driver.get(baseUrl + get); - } - -} diff --git a/samples/boot/redis-json/src/integration-test/java/sample/pages/HomePage.java b/samples/boot/redis-json/src/integration-test/java/sample/pages/HomePage.java deleted file mode 100644 index daeb6d1..0000000 --- a/samples/boot/redis-json/src/integration-test/java/sample/pages/HomePage.java +++ /dev/null @@ -1,151 +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 java.util.ArrayList; -import java.util.List; -import java.util.Set; - -import org.openqa.selenium.By; -import org.openqa.selenium.Cookie; -import org.openqa.selenium.SearchContext; -import org.openqa.selenium.WebDriver; -import org.openqa.selenium.WebElement; -import org.openqa.selenium.support.FindBy; -import org.openqa.selenium.support.PageFactory; -import org.openqa.selenium.support.pagefactory.DefaultElementLocatorFactory; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Eddú Meléndez - * @author Rob Winch - */ -public class HomePage { - - private WebDriver driver; - - @FindBy(css = "form[name=\"f\"]") - WebElement form; - - @FindBy(css = "table tbody tr") - List trs; - - List attributes; - - public HomePage(WebDriver driver) { - this.driver = driver; - this.attributes = new ArrayList(); - } - - private static void get(WebDriver driver, String get) { - String baseUrl = "http://localhost:" + System.getProperty("app.port", "8080"); - driver.get(baseUrl + get); - } - - public static T go(WebDriver driver, Class page) { - get(driver, "/"); - return PageFactory.initElements(driver, page); - } - - public void containCookie(String cookieName) { - Set cookies = this.driver.manage().getCookies(); - assertThat(cookies).extracting("name").contains(cookieName); - } - - public void doesNotContainCookie(String cookieName) { - Set cookies = this.driver.manage().getCookies(); - assertThat(cookies).extracting("name").doesNotContain(cookieName); - } - - public HomePage logout() { - WebElement logout = this.driver - .findElement(By.cssSelector("input[type=\"submit\"]")); - logout.click(); - return PageFactory.initElements(this.driver, HomePage.class); - } - - public List attributes() { - List rows = new ArrayList(); - for (WebElement tr : this.trs) { - rows.add(new Attribute(tr)); - } - this.attributes.addAll(rows); - return this.attributes; - } - - public Form form() { - return new Form(this.form); - } - - public class Form { - @FindBy(name = "key") - WebElement attributeName; - - @FindBy(name = "value") - WebElement attributeValue; - - @FindBy(css = "button[type=\"submit\"]") - WebElement submit; - - public Form(SearchContext context) { - PageFactory.initElements(new DefaultElementLocatorFactory(context), this); - } - - public Form attributeName(String text) { - this.attributeName.sendKeys(text); - return this; - } - - public Form attributeValue(String text) { - this.attributeValue.sendKeys(text); - return this; - } - - public T submit(Class page) { - this.submit.click(); - return PageFactory.initElements(HomePage.this.driver, page); - } - } - - public static class Attribute { - @FindBy(xpath = ".//td[1]") - WebElement attributeName; - - @FindBy(xpath = ".//td[2]") - WebElement attributeValue; - - public Attribute(SearchContext context) { - PageFactory.initElements(new DefaultElementLocatorFactory(context), this); - } - - /** - * @return the attributeName - */ - public String getAttributeName() { - return this.attributeName.getText(); - } - - /** - * @return the attributeValue - */ - public String getAttributeValue() { - return this.attributeValue.getText(); - } - } - -} diff --git a/samples/boot/redis-json/src/integration-test/java/sample/pages/LoginPage.java b/samples/boot/redis-json/src/integration-test/java/sample/pages/LoginPage.java deleted file mode 100644 index 18859c6..0000000 --- a/samples/boot/redis-json/src/integration-test/java/sample/pages/LoginPage.java +++ /dev/null @@ -1,69 +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.SearchContext; -import org.openqa.selenium.WebDriver; -import org.openqa.selenium.WebElement; -import org.openqa.selenium.support.FindBy; -import org.openqa.selenium.support.PageFactory; -import org.openqa.selenium.support.pagefactory.DefaultElementLocatorFactory; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Eddú Meléndez - * @author Rob Winch - */ -public class LoginPage extends BasePage { - - public LoginPage(WebDriver driver) { - super(driver); - } - - public void assertAt() { - assertThat(getDriver().getTitle()).isEqualTo("Spring Session Sample - Login"); - } - - public Form form() { - return new Form(getDriver()); - } - - public class Form { - - @FindBy(name = "username") - private WebElement username; - - @FindBy(name = "password") - private WebElement password; - - @FindBy(tagName = "button") - private WebElement button; - - public Form(SearchContext context) { - PageFactory.initElements(new DefaultElementLocatorFactory(context), this); - } - - public T login(Class page) { - this.username.sendKeys("user"); - this.password.sendKeys("password"); - this.button.click(); - return PageFactory.initElements(getDriver(), page); - } - } - -} diff --git a/samples/boot/redis-json/src/main/java/sample/Application.java b/samples/boot/redis-json/src/main/java/sample/Application.java deleted file mode 100644 index 5c988d6..0000000 --- a/samples/boot/redis-json/src/main/java/sample/Application.java +++ /dev/null @@ -1,30 +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 org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -/** - * @author jitendra on 3/3/16. - */ -@SpringBootApplication -public class Application { - - public static void main(String[] args) { - SpringApplication.run(Application.class, args); - } -} diff --git a/samples/boot/redis-json/src/main/java/sample/config/SecurityConfig.java b/samples/boot/redis-json/src/main/java/sample/config/SecurityConfig.java deleted file mode 100644 index ff865af..0000000 --- a/samples/boot/redis-json/src/main/java/sample/config/SecurityConfig.java +++ /dev/null @@ -1,54 +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.config; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; - -/** - * @author jitendra on 3/3/16. - */ -@EnableWebSecurity -public class SecurityConfig extends WebSecurityConfigurerAdapter { - - // @formatter:off - @Override - protected void configure(HttpSecurity http) throws Exception { - http - .authorizeRequests() - .antMatchers("/resources/**").permitAll() - .anyRequest().authenticated() - .and() - .formLogin() - .loginPage("/login") - .permitAll() - .and() - .logout().permitAll(); - } - // @formatter:on - - // @formatter:off - @Autowired - public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { - auth - .inMemoryAuthentication() - .withUser("user").password("password").roles("USER"); - } - // @formatter:on -} diff --git a/samples/boot/redis-json/src/main/java/sample/config/SessionConfig.java b/samples/boot/redis-json/src/main/java/sample/config/SessionConfig.java deleted file mode 100644 index fdb9c5f..0000000 --- a/samples/boot/redis-json/src/main/java/sample/config/SessionConfig.java +++ /dev/null @@ -1,68 +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.config; - -import com.fasterxml.jackson.databind.ObjectMapper; - -import org.springframework.beans.factory.BeanClassLoaderAware; -import org.springframework.context.annotation.Bean; -import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; -import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; -import org.springframework.data.redis.serializer.RedisSerializer; -import org.springframework.security.jackson2.SecurityJackson2Modules; -import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession; - -/** - * @author jitendra on 3/3/16. - */ -@EnableRedisHttpSession -public class SessionConfig implements BeanClassLoaderAware { - - private ClassLoader loader; - - @Bean - public RedisSerializer springSessionDefaultRedisSerializer() { - return new GenericJackson2JsonRedisSerializer(objectMapper()); - } - - @Bean - public LettuceConnectionFactory connectionFactory() { - return new LettuceConnectionFactory(); - } - - /** - * Customized {@link ObjectMapper} to add mix-in for class that doesn't have default - * constructors - * - * @return the {@link ObjectMapper} to use - */ - ObjectMapper objectMapper() { - ObjectMapper mapper = new ObjectMapper(); - mapper.registerModules(SecurityJackson2Modules.getModules(this.loader)); - return mapper; - } - - /* - * (non-Javadoc) - * - * @see - * org.springframework.beans.factory.BeanClassLoaderAware#setBeanClassLoader(java.lang - * .ClassLoader) - */ - public void setBeanClassLoader(ClassLoader classLoader) { - this.loader = classLoader; - } -} diff --git a/samples/boot/redis-json/src/main/java/sample/web/HomeController.java b/samples/boot/redis-json/src/main/java/sample/web/HomeController.java deleted file mode 100644 index 6d0d5ee..0000000 --- a/samples/boot/redis-json/src/main/java/sample/web/HomeController.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.web; - -import javax.servlet.http.HttpServletRequest; - -import org.springframework.stereotype.Controller; -import org.springframework.util.ObjectUtils; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; - -/** - * @author jitendra on 5/3/16. - */ -@Controller -public class HomeController { - - @RequestMapping("/") - public String home() { - return "home"; - } - - @RequestMapping("/setValue") - public String setValue(@RequestParam(name = "key", required = false) String key, - @RequestParam(name = "value", required = false) String value, - HttpServletRequest request) { - if (!ObjectUtils.isEmpty(key) && !ObjectUtils.isEmpty(value)) { - request.getSession().setAttribute(key, value); - } - return "home"; - } -} diff --git a/samples/boot/redis-json/src/main/java/sample/web/LoginController.java b/samples/boot/redis-json/src/main/java/sample/web/LoginController.java deleted file mode 100644 index 9d99b9e..0000000 --- a/samples/boot/redis-json/src/main/java/sample/web/LoginController.java +++ /dev/null @@ -1,31 +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.web; - -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.RequestMapping; - -/** - * @author jitendra on 3/3/16. - */ -@Controller -public class LoginController { - - @RequestMapping("/login") - public String login() { - return "login"; - } -} diff --git a/samples/boot/redis-json/src/main/resources/application.properties b/samples/boot/redis-json/src/main/resources/application.properties deleted file mode 100644 index 57e3e5d..0000000 --- a/samples/boot/redis-json/src/main/resources/application.properties +++ /dev/null @@ -1,3 +0,0 @@ -spring.thymeleaf.cache=false -spring.template.cache=false -#logging.level.org.springframework.security=DEBUG diff --git a/samples/boot/redis-json/src/main/resources/static/resources/css/bootstrap-responsive.css b/samples/boot/redis-json/src/main/resources/static/resources/css/bootstrap-responsive.css deleted file mode 100644 index a3352d7..0000000 --- a/samples/boot/redis-json/src/main/resources/static/resources/css/bootstrap-responsive.css +++ /dev/null @@ -1,1092 +0,0 @@ -/*! - * Bootstrap Responsive v2.2.2 - * - * Copyright 2012 Twitter, Inc - * Licensed under the Apache License v2.0 - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Designed and built with all the love in the world @twitter by @mdo and @fat. - */ - -@-ms-viewport { - width: device-width; -} - -.clearfix { - *zoom: 1; -} - -.clearfix:before, -.clearfix:after { - display: table; - line-height: 0; - content: ""; -} - -.clearfix:after { - clear: both; -} - -.hide-text { - font: 0/0 a; - color: transparent; - text-shadow: none; - background-color: transparent; - border: 0; -} - -.input-block-level { - display: block; - width: 100%; - min-height: 30px; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} - -.hidden { - display: none; - visibility: hidden; -} - -.visible-phone { - display: none !important; -} - -.visible-tablet { - display: none !important; -} - -.hidden-desktop { - display: none !important; -} - -.visible-desktop { - display: inherit !important; -} - -@media (min-width: 768px) and (max-width: 979px) { - .hidden-desktop { - display: inherit !important; - } - .visible-desktop { - display: none !important ; - } - .visible-tablet { - display: inherit !important; - } - .hidden-tablet { - display: none !important; - } -} - -@media (max-width: 767px) { - .hidden-desktop { - display: inherit !important; - } - .visible-desktop { - display: none !important; - } - .visible-phone { - display: inherit !important; - } - .hidden-phone { - display: none !important; - } -} - -@media (min-width: 1200px) { - .row { - margin-left: -30px; - *zoom: 1; - } - .row:before, - .row:after { - display: table; - line-height: 0; - content: ""; - } - .row:after { - clear: both; - } - [class*="span"] { - float: left; - min-height: 1px; - margin-left: 30px; - } - .container, - .navbar-static-top .container, - .navbar-fixed-top .container, - .navbar-fixed-bottom .container { - width: 1170px; - } - .span12 { - width: 1170px; - } - .span11 { - width: 1070px; - } - .span10 { - width: 970px; - } - .span9 { - width: 870px; - } - .span8 { - width: 770px; - } - .span7 { - width: 670px; - } - .span6 { - width: 570px; - } - .span5 { - width: 470px; - } - .span4 { - width: 370px; - } - .span3 { - width: 270px; - } - .span2 { - width: 170px; - } - .span1 { - width: 70px; - } - .offset12 { - margin-left: 1230px; - } - .offset11 { - margin-left: 1130px; - } - .offset10 { - margin-left: 1030px; - } - .offset9 { - margin-left: 930px; - } - .offset8 { - margin-left: 830px; - } - .offset7 { - margin-left: 730px; - } - .offset6 { - margin-left: 630px; - } - .offset5 { - margin-left: 530px; - } - .offset4 { - margin-left: 430px; - } - .offset3 { - margin-left: 330px; - } - .offset2 { - margin-left: 230px; - } - .offset1 { - margin-left: 130px; - } - .row-fluid { - width: 100%; - *zoom: 1; - } - .row-fluid:before, - .row-fluid:after { - display: table; - line-height: 0; - content: ""; - } - .row-fluid:after { - clear: both; - } - .row-fluid [class*="span"] { - display: block; - float: left; - width: 100%; - min-height: 30px; - margin-left: 2.564102564102564%; - *margin-left: 2.5109110747408616%; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - } - .row-fluid [class*="span"]:first-child { - margin-left: 0; - } - .row-fluid .controls-row [class*="span"] + [class*="span"] { - margin-left: 2.564102564102564%; - } - .row-fluid .span12 { - width: 100%; - *width: 99.94680851063829%; - } - .row-fluid .span11 { - width: 91.45299145299145%; - *width: 91.39979996362975%; - } - .row-fluid .span10 { - width: 82.90598290598291%; - *width: 82.8527914166212%; - } - .row-fluid .span9 { - width: 74.35897435897436%; - *width: 74.30578286961266%; - } - .row-fluid .span8 { - width: 65.81196581196582%; - *width: 65.75877432260411%; - } - .row-fluid .span7 { - width: 57.26495726495726%; - *width: 57.21176577559556%; - } - .row-fluid .span6 { - width: 48.717948717948715%; - *width: 48.664757228587014%; - } - .row-fluid .span5 { - width: 40.17094017094017%; - *width: 40.11774868157847%; - } - .row-fluid .span4 { - width: 31.623931623931625%; - *width: 31.570740134569924%; - } - .row-fluid .span3 { - width: 23.076923076923077%; - *width: 23.023731587561375%; - } - .row-fluid .span2 { - width: 14.52991452991453%; - *width: 14.476723040552828%; - } - .row-fluid .span1 { - width: 5.982905982905983%; - *width: 5.929714493544281%; - } - .row-fluid .offset12 { - margin-left: 105.12820512820512%; - *margin-left: 105.02182214948171%; - } - .row-fluid .offset12:first-child { - margin-left: 102.56410256410257%; - *margin-left: 102.45771958537915%; - } - .row-fluid .offset11 { - margin-left: 96.58119658119658%; - *margin-left: 96.47481360247316%; - } - .row-fluid .offset11:first-child { - margin-left: 94.01709401709402%; - *margin-left: 93.91071103837061%; - } - .row-fluid .offset10 { - margin-left: 88.03418803418803%; - *margin-left: 87.92780505546462%; - } - .row-fluid .offset10:first-child { - margin-left: 85.47008547008548%; - *margin-left: 85.36370249136206%; - } - .row-fluid .offset9 { - margin-left: 79.48717948717949%; - *margin-left: 79.38079650845607%; - } - .row-fluid .offset9:first-child { - margin-left: 76.92307692307693%; - *margin-left: 76.81669394435352%; - } - .row-fluid .offset8 { - margin-left: 70.94017094017094%; - *margin-left: 70.83378796144753%; - } - .row-fluid .offset8:first-child { - margin-left: 68.37606837606839%; - *margin-left: 68.26968539734497%; - } - .row-fluid .offset7 { - margin-left: 62.393162393162385%; - *margin-left: 62.28677941443899%; - } - .row-fluid .offset7:first-child { - margin-left: 59.82905982905982%; - *margin-left: 59.72267685033642%; - } - .row-fluid .offset6 { - margin-left: 53.84615384615384%; - *margin-left: 53.739770867430444%; - } - .row-fluid .offset6:first-child { - margin-left: 51.28205128205128%; - *margin-left: 51.175668303327875%; - } - .row-fluid .offset5 { - margin-left: 45.299145299145295%; - *margin-left: 45.1927623204219%; - } - .row-fluid .offset5:first-child { - margin-left: 42.73504273504273%; - *margin-left: 42.62865975631933%; - } - .row-fluid .offset4 { - margin-left: 36.75213675213675%; - *margin-left: 36.645753773413354%; - } - .row-fluid .offset4:first-child { - margin-left: 34.18803418803419%; - *margin-left: 34.081651209310785%; - } - .row-fluid .offset3 { - margin-left: 28.205128205128204%; - *margin-left: 28.0987452264048%; - } - .row-fluid .offset3:first-child { - margin-left: 25.641025641025642%; - *margin-left: 25.53464266230224%; - } - .row-fluid .offset2 { - margin-left: 19.65811965811966%; - *margin-left: 19.551736679396257%; - } - .row-fluid .offset2:first-child { - margin-left: 17.094017094017094%; - *margin-left: 16.98763411529369%; - } - .row-fluid .offset1 { - margin-left: 11.11111111111111%; - *margin-left: 11.004728132387708%; - } - .row-fluid .offset1:first-child { - margin-left: 8.547008547008547%; - *margin-left: 8.440625568285142%; - } - input, - textarea, - .uneditable-input { - margin-left: 0; - } - .controls-row [class*="span"] + [class*="span"] { - margin-left: 30px; - } - input.span12, - textarea.span12, - .uneditable-input.span12 { - width: 1156px; - } - input.span11, - textarea.span11, - .uneditable-input.span11 { - width: 1056px; - } - input.span10, - textarea.span10, - .uneditable-input.span10 { - width: 956px; - } - input.span9, - textarea.span9, - .uneditable-input.span9 { - width: 856px; - } - input.span8, - textarea.span8, - .uneditable-input.span8 { - width: 756px; - } - input.span7, - textarea.span7, - .uneditable-input.span7 { - width: 656px; - } - input.span6, - textarea.span6, - .uneditable-input.span6 { - width: 556px; - } - input.span5, - textarea.span5, - .uneditable-input.span5 { - width: 456px; - } - input.span4, - textarea.span4, - .uneditable-input.span4 { - width: 356px; - } - input.span3, - textarea.span3, - .uneditable-input.span3 { - width: 256px; - } - input.span2, - textarea.span2, - .uneditable-input.span2 { - width: 156px; - } - input.span1, - textarea.span1, - .uneditable-input.span1 { - width: 56px; - } - .thumbnails { - margin-left: -30px; - } - .thumbnails > li { - margin-left: 30px; - } - .row-fluid .thumbnails { - margin-left: 0; - } -} - -@media (min-width: 768px) and (max-width: 979px) { - .row { - margin-left: -20px; - *zoom: 1; - } - .row:before, - .row:after { - display: table; - line-height: 0; - content: ""; - } - .row:after { - clear: both; - } - [class*="span"] { - float: left; - min-height: 1px; - margin-left: 20px; - } - .container, - .navbar-static-top .container, - .navbar-fixed-top .container, - .navbar-fixed-bottom .container { - width: 724px; - } - .span12 { - width: 724px; - } - .span11 { - width: 662px; - } - .span10 { - width: 600px; - } - .span9 { - width: 538px; - } - .span8 { - width: 476px; - } - .span7 { - width: 414px; - } - .span6 { - width: 352px; - } - .span5 { - width: 290px; - } - .span4 { - width: 228px; - } - .span3 { - width: 166px; - } - .span2 { - width: 104px; - } - .span1 { - width: 42px; - } - .offset12 { - margin-left: 764px; - } - .offset11 { - margin-left: 702px; - } - .offset10 { - margin-left: 640px; - } - .offset9 { - margin-left: 578px; - } - .offset8 { - margin-left: 516px; - } - .offset7 { - margin-left: 454px; - } - .offset6 { - margin-left: 392px; - } - .offset5 { - margin-left: 330px; - } - .offset4 { - margin-left: 268px; - } - .offset3 { - margin-left: 206px; - } - .offset2 { - margin-left: 144px; - } - .offset1 { - margin-left: 82px; - } - .row-fluid { - width: 100%; - *zoom: 1; - } - .row-fluid:before, - .row-fluid:after { - display: table; - line-height: 0; - content: ""; - } - .row-fluid:after { - clear: both; - } - .row-fluid [class*="span"] { - display: block; - float: left; - width: 100%; - min-height: 30px; - margin-left: 2.7624309392265194%; - *margin-left: 2.709239449864817%; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - } - .row-fluid [class*="span"]:first-child { - margin-left: 0; - } - .row-fluid .controls-row [class*="span"] + [class*="span"] { - margin-left: 2.7624309392265194%; - } - .row-fluid .span12 { - width: 100%; - *width: 99.94680851063829%; - } - .row-fluid .span11 { - width: 91.43646408839778%; - *width: 91.38327259903608%; - } - .row-fluid .span10 { - width: 82.87292817679558%; - *width: 82.81973668743387%; - } - .row-fluid .span9 { - width: 74.30939226519337%; - *width: 74.25620077583166%; - } - .row-fluid .span8 { - width: 65.74585635359117%; - *width: 65.69266486422946%; - } - .row-fluid .span7 { - width: 57.18232044198895%; - *width: 57.12912895262725%; - } - .row-fluid .span6 { - width: 48.61878453038674%; - *width: 48.56559304102504%; - } - .row-fluid .span5 { - width: 40.05524861878453%; - *width: 40.00205712942283%; - } - .row-fluid .span4 { - width: 31.491712707182323%; - *width: 31.43852121782062%; - } - .row-fluid .span3 { - width: 22.92817679558011%; - *width: 22.87498530621841%; - } - .row-fluid .span2 { - width: 14.3646408839779%; - *width: 14.311449394616199%; - } - .row-fluid .span1 { - width: 5.801104972375691%; - *width: 5.747913483013988%; - } - .row-fluid .offset12 { - margin-left: 105.52486187845304%; - *margin-left: 105.41847889972962%; - } - .row-fluid .offset12:first-child { - margin-left: 102.76243093922652%; - *margin-left: 102.6560479605031%; - } - .row-fluid .offset11 { - margin-left: 96.96132596685082%; - *margin-left: 96.8549429881274%; - } - .row-fluid .offset11:first-child { - margin-left: 94.1988950276243%; - *margin-left: 94.09251204890089%; - } - .row-fluid .offset10 { - margin-left: 88.39779005524862%; - *margin-left: 88.2914070765252%; - } - .row-fluid .offset10:first-child { - margin-left: 85.6353591160221%; - *margin-left: 85.52897613729868%; - } - .row-fluid .offset9 { - margin-left: 79.8342541436464%; - *margin-left: 79.72787116492299%; - } - .row-fluid .offset9:first-child { - margin-left: 77.07182320441989%; - *margin-left: 76.96544022569647%; - } - .row-fluid .offset8 { - margin-left: 71.2707182320442%; - *margin-left: 71.16433525332079%; - } - .row-fluid .offset8:first-child { - margin-left: 68.50828729281768%; - *margin-left: 68.40190431409427%; - } - .row-fluid .offset7 { - margin-left: 62.70718232044199%; - *margin-left: 62.600799341718584%; - } - .row-fluid .offset7:first-child { - margin-left: 59.94475138121547%; - *margin-left: 59.838368402492065%; - } - .row-fluid .offset6 { - margin-left: 54.14364640883978%; - *margin-left: 54.037263430116376%; - } - .row-fluid .offset6:first-child { - margin-left: 51.38121546961326%; - *margin-left: 51.27483249088986%; - } - .row-fluid .offset5 { - margin-left: 45.58011049723757%; - *margin-left: 45.47372751851417%; - } - .row-fluid .offset5:first-child { - margin-left: 42.81767955801105%; - *margin-left: 42.71129657928765%; - } - .row-fluid .offset4 { - margin-left: 37.01657458563536%; - *margin-left: 36.91019160691196%; - } - .row-fluid .offset4:first-child { - margin-left: 34.25414364640884%; - *margin-left: 34.14776066768544%; - } - .row-fluid .offset3 { - margin-left: 28.45303867403315%; - *margin-left: 28.346655695309746%; - } - .row-fluid .offset3:first-child { - margin-left: 25.69060773480663%; - *margin-left: 25.584224756083227%; - } - .row-fluid .offset2 { - margin-left: 19.88950276243094%; - *margin-left: 19.783119783707537%; - } - .row-fluid .offset2:first-child { - margin-left: 17.12707182320442%; - *margin-left: 17.02068884448102%; - } - .row-fluid .offset1 { - margin-left: 11.32596685082873%; - *margin-left: 11.219583872105325%; - } - .row-fluid .offset1:first-child { - margin-left: 8.56353591160221%; - *margin-left: 8.457152932878806%; - } - input, - textarea, - .uneditable-input { - margin-left: 0; - } - .controls-row [class*="span"] + [class*="span"] { - margin-left: 20px; - } - input.span12, - textarea.span12, - .uneditable-input.span12 { - width: 710px; - } - input.span11, - textarea.span11, - .uneditable-input.span11 { - width: 648px; - } - input.span10, - textarea.span10, - .uneditable-input.span10 { - width: 586px; - } - input.span9, - textarea.span9, - .uneditable-input.span9 { - width: 524px; - } - input.span8, - textarea.span8, - .uneditable-input.span8 { - width: 462px; - } - input.span7, - textarea.span7, - .uneditable-input.span7 { - width: 400px; - } - input.span6, - textarea.span6, - .uneditable-input.span6 { - width: 338px; - } - input.span5, - textarea.span5, - .uneditable-input.span5 { - width: 276px; - } - input.span4, - textarea.span4, - .uneditable-input.span4 { - width: 214px; - } - input.span3, - textarea.span3, - .uneditable-input.span3 { - width: 152px; - } - input.span2, - textarea.span2, - .uneditable-input.span2 { - width: 90px; - } - input.span1, - textarea.span1, - .uneditable-input.span1 { - width: 28px; - } -} - -@media (max-width: 767px) { - body { - padding-right: 20px; - padding-left: 20px; - } - .navbar-fixed-top, - .navbar-fixed-bottom, - .navbar-static-top { - margin-right: -20px; - margin-left: -20px; - } - .container-fluid { - padding: 0; - } - .dl-horizontal dt { - float: none; - width: auto; - clear: none; - text-align: left; - } - .dl-horizontal dd { - margin-left: 0; - } - .container { - width: auto; - } - .row-fluid { - width: 100%; - } - .row, - .thumbnails { - margin-left: 0; - } - .thumbnails > li { - float: none; - margin-left: 0; - } - [class*="span"], - .uneditable-input[class*="span"], - .row-fluid [class*="span"] { - display: block; - float: none; - width: 100%; - margin-left: 0; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - } - .span12, - .row-fluid .span12 { - width: 100%; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - } - .row-fluid [class*="offset"]:first-child { - margin-left: 0; - } - .input-large, - .input-xlarge, - .input-xxlarge, - input[class*="span"], - select[class*="span"], - textarea[class*="span"], - .uneditable-input { - display: block; - width: 100%; - min-height: 30px; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - } - .input-prepend input, - .input-append input, - .input-prepend input[class*="span"], - .input-append input[class*="span"] { - display: inline-block; - width: auto; - } - .controls-row [class*="span"] + [class*="span"] { - margin-left: 0; - } - .modal { - position: fixed; - top: 20px; - right: 20px; - left: 20px; - width: auto; - margin: 0; - } - .modal.fade { - top: -100px; - } - .modal.fade.in { - top: 20px; - } -} - -@media (max-width: 480px) { - .nav-collapse { - -webkit-transform: translate3d(0, 0, 0); - } - .page-header h1 small { - display: block; - line-height: 20px; - } - input[type="checkbox"], - input[type="radio"] { - border: 1px solid #ccc; - } - .form-horizontal .control-label { - float: none; - width: auto; - padding-top: 0; - text-align: left; - } - .form-horizontal .controls { - margin-left: 0; - } - .form-horizontal .control-list { - padding-top: 0; - } - .form-horizontal .form-actions { - padding-right: 10px; - padding-left: 10px; - } - .media .pull-left, - .media .pull-right { - display: block; - float: none; - margin-bottom: 10px; - } - .media-object { - margin-right: 0; - margin-left: 0; - } - .modal { - top: 10px; - right: 10px; - left: 10px; - } - .modal-header .close { - padding: 10px; - margin: -10px; - } - .carousel-caption { - position: static; - } -} - -@media (max-width: 979px) { - body { - padding-top: 0; - } - .navbar-fixed-top, - .navbar-fixed-bottom { - position: static; - } - .navbar-fixed-top { - margin-bottom: 20px; - } - .navbar-fixed-bottom { - margin-top: 20px; - } - .navbar-fixed-top .navbar-inner, - .navbar-fixed-bottom .navbar-inner { - padding: 5px; - } - .navbar .container { - width: auto; - padding: 0; - } - .navbar .brand { - padding-right: 10px; - padding-left: 10px; - margin: 0 0 0 -5px; - } - .nav-collapse { - clear: both; - } - .nav-collapse .nav { - float: none; - margin: 0 0 10px; - } - .nav-collapse .nav > li { - float: none; - } - .nav-collapse .nav > li > a { - margin-bottom: 2px; - } - .nav-collapse .nav > .divider-vertical { - display: none; - } - .nav-collapse .nav .nav-header { - color: #777777; - text-shadow: none; - } - .nav-collapse .nav > li > a, - .nav-collapse .dropdown-menu a { - padding: 9px 15px; - font-weight: bold; - color: #777777; - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - border-radius: 3px; - } - .nav-collapse .btn { - padding: 4px 10px 4px; - font-weight: normal; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; - } - .nav-collapse .dropdown-menu li + li a { - margin-bottom: 2px; - } - .nav-collapse .nav > li > a:hover, - .nav-collapse .dropdown-menu a:hover { - background-color: #f2f2f2; - } - .navbar-inverse .nav-collapse .nav > li > a, - .navbar-inverse .nav-collapse .dropdown-menu a { - color: #999999; - } - .navbar-inverse .nav-collapse .nav > li > a:hover, - .navbar-inverse .nav-collapse .dropdown-menu a:hover { - background-color: #111111; - } - .nav-collapse.in .btn-group { - padding: 0; - margin-top: 5px; - } - .nav-collapse .dropdown-menu { - position: static; - top: auto; - left: auto; - display: none; - float: none; - max-width: none; - padding: 0; - margin: 0 15px; - background-color: transparent; - border: none; - -webkit-border-radius: 0; - -moz-border-radius: 0; - border-radius: 0; - -webkit-box-shadow: none; - -moz-box-shadow: none; - box-shadow: none; - } - .nav-collapse .open > .dropdown-menu { - display: block; - } - .nav-collapse .dropdown-menu:before, - .nav-collapse .dropdown-menu:after { - display: none; - } - .nav-collapse .dropdown-menu .divider { - display: none; - } - .nav-collapse .nav > li > .dropdown-menu:before, - .nav-collapse .nav > li > .dropdown-menu:after { - display: none; - } - .nav-collapse .navbar-form, - .nav-collapse .navbar-search { - float: none; - padding: 10px 15px; - margin: 10px 0; - border-top: 1px solid #f2f2f2; - border-bottom: 1px solid #f2f2f2; - -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); - -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); - box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); - } - .navbar-inverse .nav-collapse .navbar-form, - .navbar-inverse .nav-collapse .navbar-search { - border-top-color: #111111; - border-bottom-color: #111111; - } - .navbar .nav-collapse .nav.pull-right { - float: none; - margin-left: 0; - } - .nav-collapse, - .nav-collapse.collapse { - height: 0; - overflow: hidden; - } - .navbar .btn-navbar { - display: block; - } - .navbar-static .navbar-inner { - padding-right: 10px; - padding-left: 10px; - } -} - -@media (min-width: 980px) { - .nav-collapse.collapse { - height: auto !important; - overflow: visible !important; - } -} diff --git a/samples/boot/redis-json/src/main/resources/static/resources/css/bootstrap.css b/samples/boot/redis-json/src/main/resources/static/resources/css/bootstrap.css deleted file mode 100644 index 8ab3cef..0000000 --- a/samples/boot/redis-json/src/main/resources/static/resources/css/bootstrap.css +++ /dev/null @@ -1,6039 +0,0 @@ -/*! - * Bootstrap v2.2.2 - * - * Copyright 2012 Twitter, Inc - * Licensed under the Apache License v2.0 - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Designed and built with all the love in the world @twitter by @mdo and @fat. - */ - -article, -aside, -details, -figcaption, -figure, -footer, -header, -hgroup, -nav, -section { - display: block; -} - -audio, -canvas, -video { - display: inline-block; - *display: inline; - *zoom: 1; -} - -audio:not([controls]) { - display: none; -} - -html { - font-size: 100%; - -webkit-text-size-adjust: 100%; - -ms-text-size-adjust: 100%; -} - -a:focus { - outline: thin dotted #333; - outline: 5px auto -webkit-focus-ring-color; - outline-offset: -2px; -} - -a:hover, -a:active { - outline: 0; -} - -sub, -sup { - position: relative; - font-size: 75%; - line-height: 0; - vertical-align: baseline; -} - -sup { - top: -0.5em; -} - -sub { - bottom: -0.25em; -} - -img { - width: auto\9; - height: auto; - max-width: 100%; - vertical-align: middle; - border: 0; - -ms-interpolation-mode: bicubic; -} - -#map_canvas img, -.google-maps img { - max-width: none; -} - -button, -input, -select, -textarea { - margin: 0; - font-size: 100%; - vertical-align: middle; -} - -button, -input { - *overflow: visible; - line-height: normal; -} - -button::-moz-focus-inner, -input::-moz-focus-inner { - padding: 0; - border: 0; -} - -button, -html input[type="button"], -input[type="reset"], -input[type="submit"] { - cursor: pointer; - -webkit-appearance: button; -} - -label, -select, -button, -input[type="button"], -input[type="reset"], -input[type="submit"], -input[type="radio"], -input[type="checkbox"] { - cursor: pointer; -} - -input[type="search"] { - -webkit-box-sizing: content-box; - -moz-box-sizing: content-box; - box-sizing: content-box; - -webkit-appearance: textfield; -} - -input[type="search"]::-webkit-search-decoration, -input[type="search"]::-webkit-search-cancel-button { - -webkit-appearance: none; -} - -textarea { - overflow: auto; - vertical-align: top; -} - -@media print { - * { - color: #000 !important; - text-shadow: none !important; - background: transparent !important; - box-shadow: none !important; - } - a, - a:visited { - text-decoration: underline; - } - a[href]:after { - content: " (" attr(href) ")"; - } - abbr[title]:after { - content: " (" attr(title) ")"; - } - .ir a:after, - a[href^="javascript:"]:after, - a[href^="#"]:after { - content: ""; - } - pre, - blockquote { - border: 1px solid #999; - page-break-inside: avoid; - } - thead { - display: table-header-group; - } - tr, - img { - page-break-inside: avoid; - } - img { - max-width: 100% !important; - } - @page { - margin: 0.5cm; - } - p, - h2, - h3 { - orphans: 3; - widows: 3; - } - h2, - h3 { - page-break-after: avoid; - } -} - -.clearfix { - *zoom: 1; -} - -.clearfix:before, -.clearfix:after { - display: table; - line-height: 0; - content: ""; -} - -.clearfix:after { - clear: both; -} - -.hide-text { - font: 0/0 a; - color: transparent; - text-shadow: none; - background-color: transparent; - border: 0; -} - -.input-block-level { - display: block; - width: 100%; - min-height: 30px; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} - -body { - margin: 0; - font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; - font-size: 14px; - line-height: 20px; - color: #333333; - background-color: #ffffff; -} - -a { - color: #0088cc; - text-decoration: none; -} - -a:hover { - color: #005580; - text-decoration: underline; -} - -.img-rounded { - -webkit-border-radius: 6px; - -moz-border-radius: 6px; - border-radius: 6px; -} - -.img-polaroid { - padding: 4px; - background-color: #fff; - border: 1px solid #ccc; - border: 1px solid rgba(0, 0, 0, 0.2); - -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); - -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); - box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); -} - -.img-circle { - -webkit-border-radius: 500px; - -moz-border-radius: 500px; - border-radius: 500px; -} - -.row { - margin-left: -20px; - *zoom: 1; -} - -.row:before, -.row:after { - display: table; - line-height: 0; - content: ""; -} - -.row:after { - clear: both; -} - -[class*="span"] { - float: left; - min-height: 1px; - margin-left: 20px; -} - -.container, -.navbar-static-top .container, -.navbar-fixed-top .container, -.navbar-fixed-bottom .container { - width: 940px; -} - -.span12 { - width: 940px; -} - -.span11 { - width: 860px; -} - -.span10 { - width: 780px; -} - -.span9 { - width: 700px; -} - -.span8 { - width: 620px; -} - -.span7 { - width: 540px; -} - -.span6 { - width: 460px; -} - -.span5 { - width: 380px; -} - -.span4 { - width: 300px; -} - -.span3 { - width: 220px; -} - -.span2 { - width: 140px; -} - -.span1 { - width: 60px; -} - -.offset12 { - margin-left: 980px; -} - -.offset11 { - margin-left: 900px; -} - -.offset10 { - margin-left: 820px; -} - -.offset9 { - margin-left: 740px; -} - -.offset8 { - margin-left: 660px; -} - -.offset7 { - margin-left: 580px; -} - -.offset6 { - margin-left: 500px; -} - -.offset5 { - margin-left: 420px; -} - -.offset4 { - margin-left: 340px; -} - -.offset3 { - margin-left: 260px; -} - -.offset2 { - margin-left: 180px; -} - -.offset1 { - margin-left: 100px; -} - -.row-fluid { - width: 100%; - *zoom: 1; -} - -.row-fluid:before, -.row-fluid:after { - display: table; - line-height: 0; - content: ""; -} - -.row-fluid:after { - clear: both; -} - -.row-fluid [class*="span"] { - display: block; - float: left; - width: 100%; - min-height: 30px; - margin-left: 2.127659574468085%; - *margin-left: 2.074468085106383%; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} - -.row-fluid [class*="span"]:first-child { - margin-left: 0; -} - -.row-fluid .controls-row [class*="span"] + [class*="span"] { - margin-left: 2.127659574468085%; -} - -.row-fluid .span12 { - width: 100%; - *width: 99.94680851063829%; -} - -.row-fluid .span11 { - width: 91.48936170212765%; - *width: 91.43617021276594%; -} - -.row-fluid .span10 { - width: 82.97872340425532%; - *width: 82.92553191489361%; -} - -.row-fluid .span9 { - width: 74.46808510638297%; - *width: 74.41489361702126%; -} - -.row-fluid .span8 { - width: 65.95744680851064%; - *width: 65.90425531914893%; -} - -.row-fluid .span7 { - width: 57.44680851063829%; - *width: 57.39361702127659%; -} - -.row-fluid .span6 { - width: 48.93617021276595%; - *width: 48.88297872340425%; -} - -.row-fluid .span5 { - width: 40.42553191489362%; - *width: 40.37234042553192%; -} - -.row-fluid .span4 { - width: 31.914893617021278%; - *width: 31.861702127659576%; -} - -.row-fluid .span3 { - width: 23.404255319148934%; - *width: 23.351063829787233%; -} - -.row-fluid .span2 { - width: 14.893617021276595%; - *width: 14.840425531914894%; -} - -.row-fluid .span1 { - width: 6.382978723404255%; - *width: 6.329787234042553%; -} - -.row-fluid .offset12 { - margin-left: 104.25531914893617%; - *margin-left: 104.14893617021275%; -} - -.row-fluid .offset12:first-child { - margin-left: 102.12765957446808%; - *margin-left: 102.02127659574467%; -} - -.row-fluid .offset11 { - margin-left: 95.74468085106382%; - *margin-left: 95.6382978723404%; -} - -.row-fluid .offset11:first-child { - margin-left: 93.61702127659574%; - *margin-left: 93.51063829787232%; -} - -.row-fluid .offset10 { - margin-left: 87.23404255319149%; - *margin-left: 87.12765957446807%; -} - -.row-fluid .offset10:first-child { - margin-left: 85.1063829787234%; - *margin-left: 84.99999999999999%; -} - -.row-fluid .offset9 { - margin-left: 78.72340425531914%; - *margin-left: 78.61702127659572%; -} - -.row-fluid .offset9:first-child { - margin-left: 76.59574468085106%; - *margin-left: 76.48936170212764%; -} - -.row-fluid .offset8 { - margin-left: 70.2127659574468%; - *margin-left: 70.10638297872339%; -} - -.row-fluid .offset8:first-child { - margin-left: 68.08510638297872%; - *margin-left: 67.9787234042553%; -} - -.row-fluid .offset7 { - margin-left: 61.70212765957446%; - *margin-left: 61.59574468085106%; -} - -.row-fluid .offset7:first-child { - margin-left: 59.574468085106375%; - *margin-left: 59.46808510638297%; -} - -.row-fluid .offset6 { - margin-left: 53.191489361702125%; - *margin-left: 53.085106382978715%; -} - -.row-fluid .offset6:first-child { - margin-left: 51.063829787234035%; - *margin-left: 50.95744680851063%; -} - -.row-fluid .offset5 { - margin-left: 44.68085106382979%; - *margin-left: 44.57446808510638%; -} - -.row-fluid .offset5:first-child { - margin-left: 42.5531914893617%; - *margin-left: 42.4468085106383%; -} - -.row-fluid .offset4 { - margin-left: 36.170212765957444%; - *margin-left: 36.06382978723405%; -} - -.row-fluid .offset4:first-child { - margin-left: 34.04255319148936%; - *margin-left: 33.93617021276596%; -} - -.row-fluid .offset3 { - margin-left: 27.659574468085104%; - *margin-left: 27.5531914893617%; -} - -.row-fluid .offset3:first-child { - margin-left: 25.53191489361702%; - *margin-left: 25.425531914893618%; -} - -.row-fluid .offset2 { - margin-left: 19.148936170212764%; - *margin-left: 19.04255319148936%; -} - -.row-fluid .offset2:first-child { - margin-left: 17.02127659574468%; - *margin-left: 16.914893617021278%; -} - -.row-fluid .offset1 { - margin-left: 10.638297872340425%; - *margin-left: 10.53191489361702%; -} - -.row-fluid .offset1:first-child { - margin-left: 8.51063829787234%; - *margin-left: 8.404255319148938%; -} - -[class*="span"].hide, -.row-fluid [class*="span"].hide { - display: none; -} - -[class*="span"].pull-right, -.row-fluid [class*="span"].pull-right { - float: right; -} - -.container { - margin-right: auto; - margin-left: auto; - *zoom: 1; -} - -.container:before, -.container:after { - display: table; - line-height: 0; - content: ""; -} - -.container:after { - clear: both; -} - -.container-fluid { - padding-right: 20px; - padding-left: 20px; - *zoom: 1; -} - -.container-fluid:before, -.container-fluid:after { - display: table; - line-height: 0; - content: ""; -} - -.container-fluid:after { - clear: both; -} - -p { - margin: 0 0 10px; -} - -.lead { - margin-bottom: 20px; - font-size: 21px; - font-weight: 200; - line-height: 30px; -} - -small { - font-size: 85%; -} - -strong { - font-weight: bold; -} - -em { - font-style: italic; -} - -cite { - font-style: normal; -} - -.muted { - color: #999999; -} - -a.muted:hover { - color: #808080; -} - -.text-warning { - color: #c09853; -} - -a.text-warning:hover { - color: #a47e3c; -} - -.text-error { - color: #b94a48; -} - -a.text-error:hover { - color: #953b39; -} - -.text-info { - color: #3a87ad; -} - -a.text-info:hover { - color: #2d6987; -} - -.text-success { - color: #468847; -} - -a.text-success:hover { - color: #356635; -} - -h1, -h2, -h3, -h4, -h5, -h6 { - margin: 10px 0; - font-family: inherit; - font-weight: bold; - line-height: 20px; - color: inherit; - text-rendering: optimizelegibility; -} - -h1 small, -h2 small, -h3 small, -h4 small, -h5 small, -h6 small { - font-weight: normal; - line-height: 1; - color: #999999; -} - -h1, -h2, -h3 { - line-height: 40px; -} - -h1 { - font-size: 38.5px; -} - -h2 { - font-size: 31.5px; -} - -h3 { - font-size: 24.5px; -} - -h4 { - font-size: 17.5px; -} - -h5 { - font-size: 14px; -} - -h6 { - font-size: 11.9px; -} - -h1 small { - font-size: 24.5px; -} - -h2 small { - font-size: 17.5px; -} - -h3 small { - font-size: 14px; -} - -h4 small { - font-size: 14px; -} - -.page-header { - padding-bottom: 9px; - margin: 20px 0 30px; - border-bottom: 1px solid #eeeeee; -} - -ul, -ol { - padding: 0; - margin: 0 0 10px 25px; -} - -ul ul, -ul ol, -ol ol, -ol ul { - margin-bottom: 0; -} - -li { - line-height: 20px; -} - -ul.unstyled, -ol.unstyled { - margin-left: 0; - list-style: none; -} - -ul.inline, -ol.inline { - margin-left: 0; - list-style: none; -} - -ul.inline > li, -ol.inline > li { - display: inline-block; - padding-right: 5px; - padding-left: 5px; -} - -dl { - margin-bottom: 20px; -} - -dt, -dd { - line-height: 20px; -} - -dt { - font-weight: bold; -} - -dd { - margin-left: 10px; -} - -.dl-horizontal { - *zoom: 1; -} - -.dl-horizontal:before, -.dl-horizontal:after { - display: table; - line-height: 0; - content: ""; -} - -.dl-horizontal:after { - clear: both; -} - -.dl-horizontal dt { - float: left; - width: 160px; - overflow: hidden; - clear: left; - text-align: right; - text-overflow: ellipsis; - white-space: nowrap; -} - -.dl-horizontal dd { - margin-left: 180px; -} - -hr { - margin: 20px 0; - border: 0; - border-top: 1px solid #eeeeee; - border-bottom: 1px solid #ffffff; -} - -abbr[title], -abbr[data-original-title] { - cursor: help; - border-bottom: 1px dotted #999999; -} - -abbr.initialism { - font-size: 90%; - text-transform: uppercase; -} - -blockquote { - padding: 0 0 0 15px; - margin: 0 0 20px; - border-left: 5px solid #eeeeee; -} - -blockquote p { - margin-bottom: 0; - font-size: 16px; - font-weight: 300; - line-height: 25px; -} - -blockquote small { - display: block; - line-height: 20px; - color: #999999; -} - -blockquote small:before { - content: '\2014 \00A0'; -} - -blockquote.pull-right { - float: right; - padding-right: 15px; - padding-left: 0; - border-right: 5px solid #eeeeee; - border-left: 0; -} - -blockquote.pull-right p, -blockquote.pull-right small { - text-align: right; -} - -blockquote.pull-right small:before { - content: ''; -} - -blockquote.pull-right small:after { - content: '\00A0 \2014'; -} - -q:before, -q:after, -blockquote:before, -blockquote:after { - content: ""; -} - -address { - display: block; - margin-bottom: 20px; - font-style: normal; - line-height: 20px; -} - -code, -pre { - padding: 0 3px 2px; - font-family: Monaco, Menlo, Consolas, "Courier New", monospace; - font-size: 12px; - color: #333333; - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - border-radius: 3px; -} - -code { - padding: 2px 4px; - color: #d14; - white-space: nowrap; - background-color: #f7f7f9; - border: 1px solid #e1e1e8; -} - -pre { - display: block; - padding: 9.5px; - margin: 0 0 10px; - font-size: 13px; - line-height: 20px; - word-break: break-all; - word-wrap: break-word; - white-space: pre; - white-space: pre-wrap; - background-color: #f5f5f5; - border: 1px solid #ccc; - border: 1px solid rgba(0, 0, 0, 0.15); - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; -} - -pre.prettyprint { - margin-bottom: 20px; -} - -pre code { - padding: 0; - color: inherit; - white-space: pre; - white-space: pre-wrap; - background-color: transparent; - border: 0; -} - -.pre-scrollable { - max-height: 340px; - overflow-y: scroll; -} - -form { - margin: 0 0 20px; -} - -fieldset { - padding: 0; - margin: 0; - border: 0; -} - -legend { - display: block; - width: 100%; - padding: 0; - margin-bottom: 20px; - font-size: 21px; - line-height: 40px; - color: #333333; - border: 0; - border-bottom: 1px solid #e5e5e5; -} - -legend small { - font-size: 15px; - color: #999999; -} - -label, -input, -button, -select, -textarea { - font-size: 14px; - font-weight: normal; - line-height: 20px; -} - -input, -button, -select, -textarea { - font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; -} - -label { - display: block; - margin-bottom: 5px; -} - -select, -textarea, -input[type="text"], -input[type="password"], -input[type="datetime"], -input[type="datetime-local"], -input[type="date"], -input[type="month"], -input[type="time"], -input[type="week"], -input[type="number"], -input[type="email"], -input[type="url"], -input[type="search"], -input[type="tel"], -input[type="color"], -.uneditable-input { - display: inline-block; - height: 20px; - padding: 4px 6px; - margin-bottom: 10px; - font-size: 14px; - line-height: 20px; - color: #555555; - vertical-align: middle; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; -} - -input, -textarea, -.uneditable-input { - width: 206px; -} - -textarea { - height: auto; -} - -textarea, -input[type="text"], -input[type="password"], -input[type="datetime"], -input[type="datetime-local"], -input[type="date"], -input[type="month"], -input[type="time"], -input[type="week"], -input[type="number"], -input[type="email"], -input[type="url"], -input[type="search"], -input[type="tel"], -input[type="color"], -.uneditable-input { - background-color: #ffffff; - border: 1px solid #cccccc; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); - -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); - -webkit-transition: border linear 0.2s, box-shadow linear 0.2s; - -moz-transition: border linear 0.2s, box-shadow linear 0.2s; - -o-transition: border linear 0.2s, box-shadow linear 0.2s; - transition: border linear 0.2s, box-shadow linear 0.2s; -} - -textarea:focus, -input[type="text"]:focus, -input[type="password"]:focus, -input[type="datetime"]:focus, -input[type="datetime-local"]:focus, -input[type="date"]:focus, -input[type="month"]:focus, -input[type="time"]:focus, -input[type="week"]:focus, -input[type="number"]:focus, -input[type="email"]:focus, -input[type="url"]:focus, -input[type="search"]:focus, -input[type="tel"]:focus, -input[type="color"]:focus, -.uneditable-input:focus { - border-color: rgba(82, 168, 236, 0.8); - outline: 0; - outline: thin dotted \9; - /* IE6-9 */ - - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); - -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); -} - -input[type="radio"], -input[type="checkbox"] { - margin: 4px 0 0; - margin-top: 1px \9; - *margin-top: 0; - line-height: normal; -} - -input[type="file"], -input[type="image"], -input[type="submit"], -input[type="reset"], -input[type="button"], -input[type="radio"], -input[type="checkbox"] { - width: auto; -} - -select, -input[type="file"] { - height: 30px; - /* In IE7, the height of the select element cannot be changed by height, only font-size */ - - *margin-top: 4px; - /* For IE7, add top margin to align select with labels */ - - line-height: 30px; -} - -select { - width: 220px; - background-color: #ffffff; - border: 1px solid #cccccc; -} - -select[multiple], -select[size] { - height: auto; -} - -select:focus, -input[type="file"]:focus, -input[type="radio"]:focus, -input[type="checkbox"]:focus { - outline: thin dotted #333; - outline: 5px auto -webkit-focus-ring-color; - outline-offset: -2px; -} - -.uneditable-input, -.uneditable-textarea { - color: #999999; - cursor: not-allowed; - background-color: #fcfcfc; - border-color: #cccccc; - -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); - -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); - box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); -} - -.uneditable-input { - overflow: hidden; - white-space: nowrap; -} - -.uneditable-textarea { - width: auto; - height: auto; -} - -input:-moz-placeholder, -textarea:-moz-placeholder { - color: #999999; -} - -input:-ms-input-placeholder, -textarea:-ms-input-placeholder { - color: #999999; -} - -input::-webkit-input-placeholder, -textarea::-webkit-input-placeholder { - color: #999999; -} - -.radio, -.checkbox { - min-height: 20px; - padding-left: 20px; -} - -.radio input[type="radio"], -.checkbox input[type="checkbox"] { - float: left; - margin-left: -20px; -} - -.controls > .radio:first-child, -.controls > .checkbox:first-child { - padding-top: 5px; -} - -.radio.inline, -.checkbox.inline { - display: inline-block; - padding-top: 5px; - margin-bottom: 0; - vertical-align: middle; -} - -.radio.inline + .radio.inline, -.checkbox.inline + .checkbox.inline { - margin-left: 10px; -} - -.input-mini { - width: 60px; -} - -.input-small { - width: 90px; -} - -.input-medium { - width: 150px; -} - -.input-large { - width: 210px; -} - -.input-xlarge { - width: 270px; -} - -.input-xxlarge { - width: 530px; -} - -input[class*="span"], -select[class*="span"], -textarea[class*="span"], -.uneditable-input[class*="span"], -.row-fluid input[class*="span"], -.row-fluid select[class*="span"], -.row-fluid textarea[class*="span"], -.row-fluid .uneditable-input[class*="span"] { - float: none; - margin-left: 0; -} - -.input-append input[class*="span"], -.input-append .uneditable-input[class*="span"], -.input-prepend input[class*="span"], -.input-prepend .uneditable-input[class*="span"], -.row-fluid input[class*="span"], -.row-fluid select[class*="span"], -.row-fluid textarea[class*="span"], -.row-fluid .uneditable-input[class*="span"], -.row-fluid .input-prepend [class*="span"], -.row-fluid .input-append [class*="span"] { - display: inline-block; -} - -input, -textarea, -.uneditable-input { - margin-left: 0; -} - -.controls-row [class*="span"] + [class*="span"] { - margin-left: 20px; -} - -input.span12, -textarea.span12, -.uneditable-input.span12 { - width: 926px; -} - -input.span11, -textarea.span11, -.uneditable-input.span11 { - width: 846px; -} - -input.span10, -textarea.span10, -.uneditable-input.span10 { - width: 766px; -} - -input.span9, -textarea.span9, -.uneditable-input.span9 { - width: 686px; -} - -input.span8, -textarea.span8, -.uneditable-input.span8 { - width: 606px; -} - -input.span7, -textarea.span7, -.uneditable-input.span7 { - width: 526px; -} - -input.span6, -textarea.span6, -.uneditable-input.span6 { - width: 446px; -} - -input.span5, -textarea.span5, -.uneditable-input.span5 { - width: 366px; -} - -input.span4, -textarea.span4, -.uneditable-input.span4 { - width: 286px; -} - -input.span3, -textarea.span3, -.uneditable-input.span3 { - width: 206px; -} - -input.span2, -textarea.span2, -.uneditable-input.span2 { - width: 126px; -} - -input.span1, -textarea.span1, -.uneditable-input.span1 { - width: 46px; -} - -.controls-row { - *zoom: 1; -} - -.controls-row:before, -.controls-row:after { - display: table; - line-height: 0; - content: ""; -} - -.controls-row:after { - clear: both; -} - -.controls-row [class*="span"], -.row-fluid .controls-row [class*="span"] { - float: left; -} - -.controls-row .checkbox[class*="span"], -.controls-row .radio[class*="span"] { - padding-top: 5px; -} - -input[disabled], -select[disabled], -textarea[disabled], -input[readonly], -select[readonly], -textarea[readonly] { - cursor: not-allowed; - background-color: #eeeeee; -} - -input[type="radio"][disabled], -input[type="checkbox"][disabled], -input[type="radio"][readonly], -input[type="checkbox"][readonly] { - background-color: transparent; -} - -.control-group.warning .control-label, -.control-group.warning .help-block, -.control-group.warning .help-inline { - color: #c09853; -} - -.control-group.warning .checkbox, -.control-group.warning .radio, -.control-group.warning input, -.control-group.warning select, -.control-group.warning textarea { - color: #c09853; -} - -.control-group.warning input, -.control-group.warning select, -.control-group.warning textarea { - border-color: #c09853; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); - -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); -} - -.control-group.warning input:focus, -.control-group.warning select:focus, -.control-group.warning textarea:focus { - border-color: #a47e3c; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e; - -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e; - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e; -} - -.control-group.warning .input-prepend .add-on, -.control-group.warning .input-append .add-on { - color: #c09853; - background-color: #fcf8e3; - border-color: #c09853; -} - -.control-group.error .control-label, -.control-group.error .help-block, -.control-group.error .help-inline { - color: #b94a48; -} - -.control-group.error .checkbox, -.control-group.error .radio, -.control-group.error input, -.control-group.error select, -.control-group.error textarea { - color: #b94a48; -} - -.control-group.error input, -.control-group.error select, -.control-group.error textarea { - border-color: #b94a48; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); - -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); -} - -.control-group.error input:focus, -.control-group.error select:focus, -.control-group.error textarea:focus { - border-color: #953b39; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392; - -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392; - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392; -} - -.control-group.error .input-prepend .add-on, -.control-group.error .input-append .add-on { - color: #b94a48; - background-color: #f2dede; - border-color: #b94a48; -} - -.control-group.success .control-label, -.control-group.success .help-block, -.control-group.success .help-inline { - color: #468847; -} - -.control-group.success .checkbox, -.control-group.success .radio, -.control-group.success input, -.control-group.success select, -.control-group.success textarea { - color: #468847; -} - -.control-group.success input, -.control-group.success select, -.control-group.success textarea { - border-color: #468847; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); - -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); -} - -.control-group.success input:focus, -.control-group.success select:focus, -.control-group.success textarea:focus { - border-color: #356635; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b; - -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b; - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b; -} - -.control-group.success .input-prepend .add-on, -.control-group.success .input-append .add-on { - color: #468847; - background-color: #dff0d8; - border-color: #468847; -} - -.control-group.info .control-label, -.control-group.info .help-block, -.control-group.info .help-inline { - color: #3a87ad; -} - -.control-group.info .checkbox, -.control-group.info .radio, -.control-group.info input, -.control-group.info select, -.control-group.info textarea { - color: #3a87ad; -} - -.control-group.info input, -.control-group.info select, -.control-group.info textarea { - border-color: #3a87ad; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); - -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); -} - -.control-group.info input:focus, -.control-group.info select:focus, -.control-group.info textarea:focus { - border-color: #2d6987; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3; - -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3; - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3; -} - -.control-group.info .input-prepend .add-on, -.control-group.info .input-append .add-on { - color: #3a87ad; - background-color: #d9edf7; - border-color: #3a87ad; -} - -input:focus:invalid, -textarea:focus:invalid, -select:focus:invalid { - color: #b94a48; - border-color: #ee5f5b; -} - -input:focus:invalid:focus, -textarea:focus:invalid:focus, -select:focus:invalid:focus { - border-color: #e9322d; - -webkit-box-shadow: 0 0 6px #f8b9b7; - -moz-box-shadow: 0 0 6px #f8b9b7; - box-shadow: 0 0 6px #f8b9b7; -} - -.form-actions { - padding: 19px 20px 20px; - margin-top: 20px; - margin-bottom: 20px; - background-color: #f5f5f5; - border-top: 1px solid #e5e5e5; - *zoom: 1; -} - -.form-actions:before, -.form-actions:after { - display: table; - line-height: 0; - content: ""; -} - -.form-actions:after { - clear: both; -} - -.help-block, -.help-inline { - color: #595959; -} - -.help-block { - display: block; - margin-bottom: 10px; -} - -.help-inline { - display: inline-block; - *display: inline; - padding-left: 5px; - vertical-align: middle; - *zoom: 1; -} - -.input-append, -.input-prepend { - margin-bottom: 5px; - font-size: 0; - white-space: nowrap; -} - -.input-append input, -.input-prepend input, -.input-append select, -.input-prepend select, -.input-append .uneditable-input, -.input-prepend .uneditable-input, -.input-append .dropdown-menu, -.input-prepend .dropdown-menu { - font-size: 14px; -} - -.input-append input, -.input-prepend input, -.input-append select, -.input-prepend select, -.input-append .uneditable-input, -.input-prepend .uneditable-input { - position: relative; - margin-bottom: 0; - *margin-left: 0; - vertical-align: top; - -webkit-border-radius: 0 4px 4px 0; - -moz-border-radius: 0 4px 4px 0; - border-radius: 0 4px 4px 0; -} - -.input-append input:focus, -.input-prepend input:focus, -.input-append select:focus, -.input-prepend select:focus, -.input-append .uneditable-input:focus, -.input-prepend .uneditable-input:focus { - z-index: 2; -} - -.input-append .add-on, -.input-prepend .add-on { - display: inline-block; - width: auto; - height: 20px; - min-width: 16px; - padding: 4px 5px; - font-size: 14px; - font-weight: normal; - line-height: 20px; - text-align: center; - text-shadow: 0 1px 0 #ffffff; - background-color: #eeeeee; - border: 1px solid #ccc; -} - -.input-append .add-on, -.input-prepend .add-on, -.input-append .btn, -.input-prepend .btn, -.input-append .btn-group > .dropdown-toggle, -.input-prepend .btn-group > .dropdown-toggle { - vertical-align: top; - -webkit-border-radius: 0; - -moz-border-radius: 0; - border-radius: 0; -} - -.input-append .active, -.input-prepend .active { - background-color: #a9dba9; - border-color: #46a546; -} - -.input-prepend .add-on, -.input-prepend .btn { - margin-right: -1px; -} - -.input-prepend .add-on:first-child, -.input-prepend .btn:first-child { - -webkit-border-radius: 4px 0 0 4px; - -moz-border-radius: 4px 0 0 4px; - border-radius: 4px 0 0 4px; -} - -.input-append input, -.input-append select, -.input-append .uneditable-input { - -webkit-border-radius: 4px 0 0 4px; - -moz-border-radius: 4px 0 0 4px; - border-radius: 4px 0 0 4px; -} - -.input-append input + .btn-group .btn:last-child, -.input-append select + .btn-group .btn:last-child, -.input-append .uneditable-input + .btn-group .btn:last-child { - -webkit-border-radius: 0 4px 4px 0; - -moz-border-radius: 0 4px 4px 0; - border-radius: 0 4px 4px 0; -} - -.input-append .add-on, -.input-append .btn, -.input-append .btn-group { - margin-left: -1px; -} - -.input-append .add-on:last-child, -.input-append .btn:last-child, -.input-append .btn-group:last-child > .dropdown-toggle { - -webkit-border-radius: 0 4px 4px 0; - -moz-border-radius: 0 4px 4px 0; - border-radius: 0 4px 4px 0; -} - -.input-prepend.input-append input, -.input-prepend.input-append select, -.input-prepend.input-append .uneditable-input { - -webkit-border-radius: 0; - -moz-border-radius: 0; - border-radius: 0; -} - -.input-prepend.input-append input + .btn-group .btn, -.input-prepend.input-append select + .btn-group .btn, -.input-prepend.input-append .uneditable-input + .btn-group .btn { - -webkit-border-radius: 0 4px 4px 0; - -moz-border-radius: 0 4px 4px 0; - border-radius: 0 4px 4px 0; -} - -.input-prepend.input-append .add-on:first-child, -.input-prepend.input-append .btn:first-child { - margin-right: -1px; - -webkit-border-radius: 4px 0 0 4px; - -moz-border-radius: 4px 0 0 4px; - border-radius: 4px 0 0 4px; -} - -.input-prepend.input-append .add-on:last-child, -.input-prepend.input-append .btn:last-child { - margin-left: -1px; - -webkit-border-radius: 0 4px 4px 0; - -moz-border-radius: 0 4px 4px 0; - border-radius: 0 4px 4px 0; -} - -.input-prepend.input-append .btn-group:first-child { - margin-left: 0; -} - -input.search-query { - padding-right: 14px; - padding-right: 4px \9; - padding-left: 14px; - padding-left: 4px \9; - /* IE7-8 doesn't have border-radius, so don't indent the padding */ - - margin-bottom: 0; - -webkit-border-radius: 15px; - -moz-border-radius: 15px; - border-radius: 15px; -} - -/* Allow for input prepend/append in search forms */ - -.form-search .input-append .search-query, -.form-search .input-prepend .search-query { - -webkit-border-radius: 0; - -moz-border-radius: 0; - border-radius: 0; -} - -.form-search .input-append .search-query { - -webkit-border-radius: 14px 0 0 14px; - -moz-border-radius: 14px 0 0 14px; - border-radius: 14px 0 0 14px; -} - -.form-search .input-append .btn { - -webkit-border-radius: 0 14px 14px 0; - -moz-border-radius: 0 14px 14px 0; - border-radius: 0 14px 14px 0; -} - -.form-search .input-prepend .search-query { - -webkit-border-radius: 0 14px 14px 0; - -moz-border-radius: 0 14px 14px 0; - border-radius: 0 14px 14px 0; -} - -.form-search .input-prepend .btn { - -webkit-border-radius: 14px 0 0 14px; - -moz-border-radius: 14px 0 0 14px; - border-radius: 14px 0 0 14px; -} - -.form-search input, -.form-inline input, -.form-horizontal input, -.form-search textarea, -.form-inline textarea, -.form-horizontal textarea, -.form-search select, -.form-inline select, -.form-horizontal select, -.form-search .help-inline, -.form-inline .help-inline, -.form-horizontal .help-inline, -.form-search .uneditable-input, -.form-inline .uneditable-input, -.form-horizontal .uneditable-input, -.form-search .input-prepend, -.form-inline .input-prepend, -.form-horizontal .input-prepend, -.form-search .input-append, -.form-inline .input-append, -.form-horizontal .input-append { - display: inline-block; - *display: inline; - margin-bottom: 0; - vertical-align: middle; - *zoom: 1; -} - -.form-search .hide, -.form-inline .hide, -.form-horizontal .hide { - display: none; -} - -.form-search label, -.form-inline label, -.form-search .btn-group, -.form-inline .btn-group { - display: inline-block; -} - -.form-search .input-append, -.form-inline .input-append, -.form-search .input-prepend, -.form-inline .input-prepend { - margin-bottom: 0; -} - -.form-search .radio, -.form-search .checkbox, -.form-inline .radio, -.form-inline .checkbox { - padding-left: 0; - margin-bottom: 0; - vertical-align: middle; -} - -.form-search .radio input[type="radio"], -.form-search .checkbox input[type="checkbox"], -.form-inline .radio input[type="radio"], -.form-inline .checkbox input[type="checkbox"] { - float: left; - margin-right: 3px; - margin-left: 0; -} - -.control-group { - margin-bottom: 10px; -} - -legend + .control-group { - margin-top: 20px; - -webkit-margin-top-collapse: separate; -} - -.form-horizontal .control-group { - margin-bottom: 20px; - *zoom: 1; -} - -.form-horizontal .control-group:before, -.form-horizontal .control-group:after { - display: table; - line-height: 0; - content: ""; -} - -.form-horizontal .control-group:after { - clear: both; -} - -.form-horizontal .control-label { - float: left; - width: 160px; - padding-top: 5px; - text-align: right; -} - -.form-horizontal .controls { - *display: inline-block; - *padding-left: 20px; - margin-left: 180px; - *margin-left: 0; -} - -.form-horizontal .controls:first-child { - *padding-left: 180px; -} - -.form-horizontal .help-block { - margin-bottom: 0; -} - -.form-horizontal input + .help-block, -.form-horizontal select + .help-block, -.form-horizontal textarea + .help-block, -.form-horizontal .uneditable-input + .help-block, -.form-horizontal .input-prepend + .help-block, -.form-horizontal .input-append + .help-block { - margin-top: 10px; -} - -.form-horizontal .form-actions { - padding-left: 180px; -} - -table { - max-width: 100%; - background-color: transparent; - border-collapse: collapse; - border-spacing: 0; -} - -.table { - width: 100%; - margin-bottom: 20px; -} - -.table th, -.table td { - padding: 8px; - line-height: 20px; - text-align: left; - vertical-align: top; - border-top: 1px solid #dddddd; -} - -.table th { - font-weight: bold; -} - -.table thead th { - vertical-align: bottom; -} - -.table caption + thead tr:first-child th, -.table caption + thead tr:first-child td, -.table colgroup + thead tr:first-child th, -.table colgroup + thead tr:first-child td, -.table thead:first-child tr:first-child th, -.table thead:first-child tr:first-child td { - border-top: 0; -} - -.table tbody + tbody { - border-top: 2px solid #dddddd; -} - -.table .table { - background-color: #ffffff; -} - -.table-condensed th, -.table-condensed td { - padding: 4px 5px; -} - -.table-bordered { - border: 1px solid #dddddd; - border-collapse: separate; - *border-collapse: collapse; - border-left: 0; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; -} - -.table-bordered th, -.table-bordered td { - border-left: 1px solid #dddddd; -} - -.table-bordered caption + thead tr:first-child th, -.table-bordered caption + tbody tr:first-child th, -.table-bordered caption + tbody tr:first-child td, -.table-bordered colgroup + thead tr:first-child th, -.table-bordered colgroup + tbody tr:first-child th, -.table-bordered colgroup + tbody tr:first-child td, -.table-bordered thead:first-child tr:first-child th, -.table-bordered tbody:first-child tr:first-child th, -.table-bordered tbody:first-child tr:first-child td { - border-top: 0; -} - -.table-bordered thead:first-child tr:first-child > th:first-child, -.table-bordered tbody:first-child tr:first-child > td:first-child { - -webkit-border-top-left-radius: 4px; - border-top-left-radius: 4px; - -moz-border-radius-topleft: 4px; -} - -.table-bordered thead:first-child tr:first-child > th:last-child, -.table-bordered tbody:first-child tr:first-child > td:last-child { - -webkit-border-top-right-radius: 4px; - border-top-right-radius: 4px; - -moz-border-radius-topright: 4px; -} - -.table-bordered thead:last-child tr:last-child > th:first-child, -.table-bordered tbody:last-child tr:last-child > td:first-child, -.table-bordered tfoot:last-child tr:last-child > td:first-child { - -webkit-border-bottom-left-radius: 4px; - border-bottom-left-radius: 4px; - -moz-border-radius-bottomleft: 4px; -} - -.table-bordered thead:last-child tr:last-child > th:last-child, -.table-bordered tbody:last-child tr:last-child > td:last-child, -.table-bordered tfoot:last-child tr:last-child > td:last-child { - -webkit-border-bottom-right-radius: 4px; - border-bottom-right-radius: 4px; - -moz-border-radius-bottomright: 4px; -} - -.table-bordered tfoot + tbody:last-child tr:last-child td:first-child { - -webkit-border-bottom-left-radius: 0; - border-bottom-left-radius: 0; - -moz-border-radius-bottomleft: 0; -} - -.table-bordered tfoot + tbody:last-child tr:last-child td:last-child { - -webkit-border-bottom-right-radius: 0; - border-bottom-right-radius: 0; - -moz-border-radius-bottomright: 0; -} - -.table-bordered caption + thead tr:first-child th:first-child, -.table-bordered caption + tbody tr:first-child td:first-child, -.table-bordered colgroup + thead tr:first-child th:first-child, -.table-bordered colgroup + tbody tr:first-child td:first-child { - -webkit-border-top-left-radius: 4px; - border-top-left-radius: 4px; - -moz-border-radius-topleft: 4px; -} - -.table-bordered caption + thead tr:first-child th:last-child, -.table-bordered caption + tbody tr:first-child td:last-child, -.table-bordered colgroup + thead tr:first-child th:last-child, -.table-bordered colgroup + tbody tr:first-child td:last-child { - -webkit-border-top-right-radius: 4px; - border-top-right-radius: 4px; - -moz-border-radius-topright: 4px; -} - -.table-striped tbody > tr:nth-child(odd) > td, -.table-striped tbody > tr:nth-child(odd) > th { - background-color: #f9f9f9; -} - -.table-hover tbody tr:hover td, -.table-hover tbody tr:hover th { - background-color: #f5f5f5; -} - -table td[class*="span"], -table th[class*="span"], -.row-fluid table td[class*="span"], -.row-fluid table th[class*="span"] { - display: table-cell; - float: none; - margin-left: 0; -} - -.table td.span1, -.table th.span1 { - float: none; - width: 44px; - margin-left: 0; -} - -.table td.span2, -.table th.span2 { - float: none; - width: 124px; - margin-left: 0; -} - -.table td.span3, -.table th.span3 { - float: none; - width: 204px; - margin-left: 0; -} - -.table td.span4, -.table th.span4 { - float: none; - width: 284px; - margin-left: 0; -} - -.table td.span5, -.table th.span5 { - float: none; - width: 364px; - margin-left: 0; -} - -.table td.span6, -.table th.span6 { - float: none; - width: 444px; - margin-left: 0; -} - -.table td.span7, -.table th.span7 { - float: none; - width: 524px; - margin-left: 0; -} - -.table td.span8, -.table th.span8 { - float: none; - width: 604px; - margin-left: 0; -} - -.table td.span9, -.table th.span9 { - float: none; - width: 684px; - margin-left: 0; -} - -.table td.span10, -.table th.span10 { - float: none; - width: 764px; - margin-left: 0; -} - -.table td.span11, -.table th.span11 { - float: none; - width: 844px; - margin-left: 0; -} - -.table td.span12, -.table th.span12 { - float: none; - width: 924px; - margin-left: 0; -} - -.table tbody tr.success td { - background-color: #dff0d8; -} - -.table tbody tr.error td { - background-color: #f2dede; -} - -.table tbody tr.warning td { - background-color: #fcf8e3; -} - -.table tbody tr.info td { - background-color: #d9edf7; -} - -.table-hover tbody tr.success:hover td { - background-color: #d0e9c6; -} - -.table-hover tbody tr.error:hover td { - background-color: #ebcccc; -} - -.table-hover tbody tr.warning:hover td { - background-color: #faf2cc; -} - -.table-hover tbody tr.info:hover td { - background-color: #c4e3f3; -} - -[class^="icon-"], -[class*=" icon-"] { - display: inline-block; - width: 14px; - height: 14px; - margin-top: 1px; - *margin-right: .3em; - line-height: 14px; - vertical-align: text-top; - background-image: url("../img/glyphicons-halflings.png"); - background-position: 14px 14px; - background-repeat: no-repeat; -} - -/* White icons with optional class, or on hover/active states of certain elements */ - -.icon-white, -.nav-pills > .active > a > [class^="icon-"], -.nav-pills > .active > a > [class*=" icon-"], -.nav-list > .active > a > [class^="icon-"], -.nav-list > .active > a > [class*=" icon-"], -.navbar-inverse .nav > .active > a > [class^="icon-"], -.navbar-inverse .nav > .active > a > [class*=" icon-"], -.dropdown-menu > li > a:hover > [class^="icon-"], -.dropdown-menu > li > a:hover > [class*=" icon-"], -.dropdown-menu > .active > a > [class^="icon-"], -.dropdown-menu > .active > a > [class*=" icon-"], -.dropdown-submenu:hover > a > [class^="icon-"], -.dropdown-submenu:hover > a > [class*=" icon-"] { - background-image: url("../img/glyphicons-halflings-white.png"); -} - -.icon-glass { - background-position: 0 0; -} - -.icon-music { - background-position: -24px 0; -} - -.icon-search { - background-position: -48px 0; -} - -.icon-envelope { - background-position: -72px 0; -} - -.icon-heart { - background-position: -96px 0; -} - -.icon-star { - background-position: -120px 0; -} - -.icon-star-empty { - background-position: -144px 0; -} - -.icon-user { - background-position: -168px 0; -} - -.icon-film { - background-position: -192px 0; -} - -.icon-th-large { - background-position: -216px 0; -} - -.icon-th { - background-position: -240px 0; -} - -.icon-th-list { - background-position: -264px 0; -} - -.icon-ok { - background-position: -288px 0; -} - -.icon-remove { - background-position: -312px 0; -} - -.icon-zoom-in { - background-position: -336px 0; -} - -.icon-zoom-out { - background-position: -360px 0; -} - -.icon-off { - background-position: -384px 0; -} - -.icon-signal { - background-position: -408px 0; -} - -.icon-cog { - background-position: -432px 0; -} - -.icon-trash { - background-position: -456px 0; -} - -.icon-home { - background-position: 0 -24px; -} - -.icon-file { - background-position: -24px -24px; -} - -.icon-time { - background-position: -48px -24px; -} - -.icon-road { - background-position: -72px -24px; -} - -.icon-download-alt { - background-position: -96px -24px; -} - -.icon-download { - background-position: -120px -24px; -} - -.icon-upload { - background-position: -144px -24px; -} - -.icon-inbox { - background-position: -168px -24px; -} - -.icon-play-circle { - background-position: -192px -24px; -} - -.icon-repeat { - background-position: -216px -24px; -} - -.icon-refresh { - background-position: -240px -24px; -} - -.icon-list-alt { - background-position: -264px -24px; -} - -.icon-lock { - background-position: -287px -24px; -} - -.icon-flag { - background-position: -312px -24px; -} - -.icon-headphones { - background-position: -336px -24px; -} - -.icon-volume-off { - background-position: -360px -24px; -} - -.icon-volume-down { - background-position: -384px -24px; -} - -.icon-volume-up { - background-position: -408px -24px; -} - -.icon-qrcode { - background-position: -432px -24px; -} - -.icon-barcode { - background-position: -456px -24px; -} - -.icon-tag { - background-position: 0 -48px; -} - -.icon-tags { - background-position: -25px -48px; -} - -.icon-book { - background-position: -48px -48px; -} - -.icon-bookmark { - background-position: -72px -48px; -} - -.icon-print { - background-position: -96px -48px; -} - -.icon-camera { - background-position: -120px -48px; -} - -.icon-font { - background-position: -144px -48px; -} - -.icon-bold { - background-position: -167px -48px; -} - -.icon-italic { - background-position: -192px -48px; -} - -.icon-text-height { - background-position: -216px -48px; -} - -.icon-text-width { - background-position: -240px -48px; -} - -.icon-align-left { - background-position: -264px -48px; -} - -.icon-align-center { - background-position: -288px -48px; -} - -.icon-align-right { - background-position: -312px -48px; -} - -.icon-align-justify { - background-position: -336px -48px; -} - -.icon-list { - background-position: -360px -48px; -} - -.icon-indent-left { - background-position: -384px -48px; -} - -.icon-indent-right { - background-position: -408px -48px; -} - -.icon-facetime-video { - background-position: -432px -48px; -} - -.icon-picture { - background-position: -456px -48px; -} - -.icon-pencil { - background-position: 0 -72px; -} - -.icon-map-marker { - background-position: -24px -72px; -} - -.icon-adjust { - background-position: -48px -72px; -} - -.icon-tint { - background-position: -72px -72px; -} - -.icon-edit { - background-position: -96px -72px; -} - -.icon-share { - background-position: -120px -72px; -} - -.icon-check { - background-position: -144px -72px; -} - -.icon-move { - background-position: -168px -72px; -} - -.icon-step-backward { - background-position: -192px -72px; -} - -.icon-fast-backward { - background-position: -216px -72px; -} - -.icon-backward { - background-position: -240px -72px; -} - -.icon-play { - background-position: -264px -72px; -} - -.icon-pause { - background-position: -288px -72px; -} - -.icon-stop { - background-position: -312px -72px; -} - -.icon-forward { - background-position: -336px -72px; -} - -.icon-fast-forward { - background-position: -360px -72px; -} - -.icon-step-forward { - background-position: -384px -72px; -} - -.icon-eject { - background-position: -408px -72px; -} - -.icon-chevron-left { - background-position: -432px -72px; -} - -.icon-chevron-right { - background-position: -456px -72px; -} - -.icon-plus-sign { - background-position: 0 -96px; -} - -.icon-minus-sign { - background-position: -24px -96px; -} - -.icon-remove-sign { - background-position: -48px -96px; -} - -.icon-ok-sign { - background-position: -72px -96px; -} - -.icon-question-sign { - background-position: -96px -96px; -} - -.icon-info-sign { - background-position: -120px -96px; -} - -.icon-screenshot { - background-position: -144px -96px; -} - -.icon-remove-circle { - background-position: -168px -96px; -} - -.icon-ok-circle { - background-position: -192px -96px; -} - -.icon-ban-circle { - background-position: -216px -96px; -} - -.icon-arrow-left { - background-position: -240px -96px; -} - -.icon-arrow-right { - background-position: -264px -96px; -} - -.icon-arrow-up { - background-position: -289px -96px; -} - -.icon-arrow-down { - background-position: -312px -96px; -} - -.icon-share-alt { - background-position: -336px -96px; -} - -.icon-resize-full { - background-position: -360px -96px; -} - -.icon-resize-small { - background-position: -384px -96px; -} - -.icon-plus { - background-position: -408px -96px; -} - -.icon-minus { - background-position: -433px -96px; -} - -.icon-asterisk { - background-position: -456px -96px; -} - -.icon-exclamation-sign { - background-position: 0 -120px; -} - -.icon-gift { - background-position: -24px -120px; -} - -.icon-leaf { - background-position: -48px -120px; -} - -.icon-fire { - background-position: -72px -120px; -} - -.icon-eye-open { - background-position: -96px -120px; -} - -.icon-eye-close { - background-position: -120px -120px; -} - -.icon-warning-sign { - background-position: -144px -120px; -} - -.icon-plane { - background-position: -168px -120px; -} - -.icon-calendar { - background-position: -192px -120px; -} - -.icon-random { - width: 16px; - background-position: -216px -120px; -} - -.icon-comment { - background-position: -240px -120px; -} - -.icon-magnet { - background-position: -264px -120px; -} - -.icon-chevron-up { - background-position: -288px -120px; -} - -.icon-chevron-down { - background-position: -313px -119px; -} - -.icon-retweet { - background-position: -336px -120px; -} - -.icon-shopping-cart { - background-position: -360px -120px; -} - -.icon-folder-close { - background-position: -384px -120px; -} - -.icon-folder-open { - width: 16px; - background-position: -408px -120px; -} - -.icon-resize-vertical { - background-position: -432px -119px; -} - -.icon-resize-horizontal { - background-position: -456px -118px; -} - -.icon-hdd { - background-position: 0 -144px; -} - -.icon-bullhorn { - background-position: -24px -144px; -} - -.icon-bell { - background-position: -48px -144px; -} - -.icon-certificate { - background-position: -72px -144px; -} - -.icon-thumbs-up { - background-position: -96px -144px; -} - -.icon-thumbs-down { - background-position: -120px -144px; -} - -.icon-hand-right { - background-position: -144px -144px; -} - -.icon-hand-left { - background-position: -168px -144px; -} - -.icon-hand-up { - background-position: -192px -144px; -} - -.icon-hand-down { - background-position: -216px -144px; -} - -.icon-circle-arrow-right { - background-position: -240px -144px; -} - -.icon-circle-arrow-left { - background-position: -264px -144px; -} - -.icon-circle-arrow-up { - background-position: -288px -144px; -} - -.icon-circle-arrow-down { - background-position: -312px -144px; -} - -.icon-globe { - background-position: -336px -144px; -} - -.icon-wrench { - background-position: -360px -144px; -} - -.icon-tasks { - background-position: -384px -144px; -} - -.icon-filter { - background-position: -408px -144px; -} - -.icon-briefcase { - background-position: -432px -144px; -} - -.icon-fullscreen { - background-position: -456px -144px; -} - -.dropup, -.dropdown { - position: relative; -} - -.dropdown-toggle { - *margin-bottom: -3px; -} - -.dropdown-toggle:active, -.open .dropdown-toggle { - outline: 0; -} - -.caret { - display: inline-block; - width: 0; - height: 0; - vertical-align: top; - border-top: 4px solid #000000; - border-right: 4px solid transparent; - border-left: 4px solid transparent; - content: ""; -} - -.dropdown .caret { - margin-top: 8px; - margin-left: 2px; -} - -.dropdown-menu { - position: absolute; - top: 100%; - left: 0; - z-index: 1000; - display: none; - float: left; - min-width: 160px; - padding: 5px 0; - margin: 2px 0 0; - list-style: none; - background-color: #ffffff; - border: 1px solid #ccc; - border: 1px solid rgba(0, 0, 0, 0.2); - *border-right-width: 2px; - *border-bottom-width: 2px; - -webkit-border-radius: 6px; - -moz-border-radius: 6px; - border-radius: 6px; - -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); - -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); - box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); - -webkit-background-clip: padding-box; - -moz-background-clip: padding; - background-clip: padding-box; -} - -.dropdown-menu.pull-right { - right: 0; - left: auto; -} - -.dropdown-menu .divider { - *width: 100%; - height: 1px; - margin: 9px 1px; - *margin: -5px 0 5px; - overflow: hidden; - background-color: #e5e5e5; - border-bottom: 1px solid #ffffff; -} - -.dropdown-menu li > a { - display: block; - padding: 3px 20px; - clear: both; - font-weight: normal; - line-height: 20px; - color: #333333; - white-space: nowrap; -} - -.dropdown-menu li > a:hover, -.dropdown-menu li > a:focus, -.dropdown-submenu:hover > a { - color: #ffffff; - text-decoration: none; - background-color: #0081c2; - background-image: -moz-linear-gradient(top, #0088cc, #0077b3); - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3)); - background-image: -webkit-linear-gradient(top, #0088cc, #0077b3); - background-image: -o-linear-gradient(top, #0088cc, #0077b3); - background-image: linear-gradient(to bottom, #0088cc, #0077b3); - background-repeat: repeat-x; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0); -} - -.dropdown-menu .active > a, -.dropdown-menu .active > a:hover { - color: #ffffff; - text-decoration: none; - background-color: #0081c2; - background-image: -moz-linear-gradient(top, #0088cc, #0077b3); - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3)); - background-image: -webkit-linear-gradient(top, #0088cc, #0077b3); - background-image: -o-linear-gradient(top, #0088cc, #0077b3); - background-image: linear-gradient(to bottom, #0088cc, #0077b3); - background-repeat: repeat-x; - outline: 0; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0); -} - -.dropdown-menu .disabled > a, -.dropdown-menu .disabled > a:hover { - color: #999999; -} - -.dropdown-menu .disabled > a:hover { - text-decoration: none; - cursor: default; - background-color: transparent; - background-image: none; - filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); -} - -.open { - *z-index: 1000; -} - -.open > .dropdown-menu { - display: block; -} - -.pull-right > .dropdown-menu { - right: 0; - left: auto; -} - -.dropup .caret, -.navbar-fixed-bottom .dropdown .caret { - border-top: 0; - border-bottom: 4px solid #000000; - content: ""; -} - -.dropup .dropdown-menu, -.navbar-fixed-bottom .dropdown .dropdown-menu { - top: auto; - bottom: 100%; - margin-bottom: 1px; -} - -.dropdown-submenu { - position: relative; -} - -.dropdown-submenu > .dropdown-menu { - top: 0; - left: 100%; - margin-top: -6px; - margin-left: -1px; - -webkit-border-radius: 0 6px 6px 6px; - -moz-border-radius: 0 6px 6px 6px; - border-radius: 0 6px 6px 6px; -} - -.dropdown-submenu:hover > .dropdown-menu { - display: block; -} - -.dropup .dropdown-submenu > .dropdown-menu { - top: auto; - bottom: 0; - margin-top: 0; - margin-bottom: -2px; - -webkit-border-radius: 5px 5px 5px 0; - -moz-border-radius: 5px 5px 5px 0; - border-radius: 5px 5px 5px 0; -} - -.dropdown-submenu > a:after { - display: block; - float: right; - width: 0; - height: 0; - margin-top: 5px; - margin-right: -10px; - border-color: transparent; - border-left-color: #cccccc; - border-style: solid; - border-width: 5px 0 5px 5px; - content: " "; -} - -.dropdown-submenu:hover > a:after { - border-left-color: #ffffff; -} - -.dropdown-submenu.pull-left { - float: none; -} - -.dropdown-submenu.pull-left > .dropdown-menu { - left: -100%; - margin-left: 10px; - -webkit-border-radius: 6px 0 6px 6px; - -moz-border-radius: 6px 0 6px 6px; - border-radius: 6px 0 6px 6px; -} - -.dropdown .dropdown-menu .nav-header { - padding-right: 20px; - padding-left: 20px; -} - -.typeahead { - z-index: 1051; - margin-top: 2px; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; -} - -.well { - min-height: 20px; - padding: 19px; - margin-bottom: 20px; - background-color: #f5f5f5; - border: 1px solid #e3e3e3; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); - -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); -} - -.well blockquote { - border-color: #ddd; - border-color: rgba(0, 0, 0, 0.15); -} - -.well-large { - padding: 24px; - -webkit-border-radius: 6px; - -moz-border-radius: 6px; - border-radius: 6px; -} - -.well-small { - padding: 9px; - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - border-radius: 3px; -} - -.fade { - opacity: 0; - -webkit-transition: opacity 0.15s linear; - -moz-transition: opacity 0.15s linear; - -o-transition: opacity 0.15s linear; - transition: opacity 0.15s linear; -} - -.fade.in { - opacity: 1; -} - -.collapse { - position: relative; - height: 0; - overflow: hidden; - -webkit-transition: height 0.35s ease; - -moz-transition: height 0.35s ease; - -o-transition: height 0.35s ease; - transition: height 0.35s ease; -} - -.collapse.in { - height: auto; -} - -.close { - float: right; - font-size: 20px; - font-weight: bold; - line-height: 20px; - color: #000000; - text-shadow: 0 1px 0 #ffffff; - opacity: 0.2; - filter: alpha(opacity=20); -} - -.close:hover { - color: #000000; - text-decoration: none; - cursor: pointer; - opacity: 0.4; - filter: alpha(opacity=40); -} - -button.close { - padding: 0; - cursor: pointer; - background: transparent; - border: 0; - -webkit-appearance: none; -} - -.btn { - display: inline-block; - *display: inline; - padding: 4px 12px; - margin-bottom: 0; - *margin-left: .3em; - font-size: 14px; - line-height: 20px; - color: #333333; - text-align: center; - text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); - vertical-align: middle; - cursor: pointer; - background-color: #f5f5f5; - *background-color: #e6e6e6; - background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6); - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6)); - background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6); - background-image: -o-linear-gradient(top, #ffffff, #e6e6e6); - background-image: linear-gradient(to bottom, #ffffff, #e6e6e6); - background-repeat: repeat-x; - border: 1px solid #bbbbbb; - *border: 0; - border-color: #e6e6e6 #e6e6e6 #bfbfbf; - border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); - border-bottom-color: #a2a2a2; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe6e6e6', GradientType=0); - filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); - *zoom: 1; - -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); - -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); - box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); -} - -.btn:hover, -.btn:active, -.btn.active, -.btn.disabled, -.btn[disabled] { - color: #333333; - background-color: #e6e6e6; - *background-color: #d9d9d9; -} - -.btn:active, -.btn.active { - background-color: #cccccc \9; -} - -.btn:first-child { - *margin-left: 0; -} - -.btn:hover { - color: #333333; - text-decoration: none; - background-position: 0 -15px; - -webkit-transition: background-position 0.1s linear; - -moz-transition: background-position 0.1s linear; - -o-transition: background-position 0.1s linear; - transition: background-position 0.1s linear; -} - -.btn:focus { - outline: thin dotted #333; - outline: 5px auto -webkit-focus-ring-color; - outline-offset: -2px; -} - -.btn.active, -.btn:active { - background-image: none; - outline: 0; - -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); - -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); - box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); -} - -.btn.disabled, -.btn[disabled] { - cursor: default; - background-image: none; - opacity: 0.65; - filter: alpha(opacity=65); - -webkit-box-shadow: none; - -moz-box-shadow: none; - box-shadow: none; -} - -.btn-large { - padding: 11px 19px; - font-size: 17.5px; - -webkit-border-radius: 6px; - -moz-border-radius: 6px; - border-radius: 6px; -} - -.btn-large [class^="icon-"], -.btn-large [class*=" icon-"] { - margin-top: 4px; -} - -.btn-small { - padding: 2px 10px; - font-size: 11.9px; - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - border-radius: 3px; -} - -.btn-small [class^="icon-"], -.btn-small [class*=" icon-"] { - margin-top: 0; -} - -.btn-mini [class^="icon-"], -.btn-mini [class*=" icon-"] { - margin-top: -1px; -} - -.btn-mini { - padding: 0 6px; - font-size: 10.5px; - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - border-radius: 3px; -} - -.btn-block { - display: block; - width: 100%; - padding-right: 0; - padding-left: 0; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} - -.btn-block + .btn-block { - margin-top: 5px; -} - -input[type="submit"].btn-block, -input[type="reset"].btn-block, -input[type="button"].btn-block { - width: 100%; -} - -.btn-primary.active, -.btn-warning.active, -.btn-danger.active, -.btn-success.active, -.btn-info.active, -.btn-inverse.active { - color: rgba(255, 255, 255, 0.75); -} - -.btn { - border-color: #c5c5c5; - border-color: rgba(0, 0, 0, 0.15) rgba(0, 0, 0, 0.15) rgba(0, 0, 0, 0.25); -} - -.btn-primary { - color: #ffffff; - text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); - background-color: #006dcc; - *background-color: #0044cc; - background-image: -moz-linear-gradient(top, #0088cc, #0044cc); - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); - background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); - background-image: -o-linear-gradient(top, #0088cc, #0044cc); - background-image: linear-gradient(to bottom, #0088cc, #0044cc); - background-repeat: repeat-x; - border-color: #0044cc #0044cc #002a80; - border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0044cc', GradientType=0); - filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); -} - -.btn-primary:hover, -.btn-primary:active, -.btn-primary.active, -.btn-primary.disabled, -.btn-primary[disabled] { - color: #ffffff; - background-color: #0044cc; - *background-color: #003bb3; -} - -.btn-primary:active, -.btn-primary.active { - background-color: #003399 \9; -} - -.btn-warning { - color: #ffffff; - text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); - background-color: #faa732; - *background-color: #f89406; - background-image: -moz-linear-gradient(top, #fbb450, #f89406); - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406)); - background-image: -webkit-linear-gradient(top, #fbb450, #f89406); - background-image: -o-linear-gradient(top, #fbb450, #f89406); - background-image: linear-gradient(to bottom, #fbb450, #f89406); - background-repeat: repeat-x; - border-color: #f89406 #f89406 #ad6704; - border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0); - filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); -} - -.btn-warning:hover, -.btn-warning:active, -.btn-warning.active, -.btn-warning.disabled, -.btn-warning[disabled] { - color: #ffffff; - background-color: #f89406; - *background-color: #df8505; -} - -.btn-warning:active, -.btn-warning.active { - background-color: #c67605 \9; -} - -.btn-danger { - color: #ffffff; - text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); - background-color: #da4f49; - *background-color: #bd362f; - background-image: -moz-linear-gradient(top, #ee5f5b, #bd362f); - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f)); - background-image: -webkit-linear-gradient(top, #ee5f5b, #bd362f); - background-image: -o-linear-gradient(top, #ee5f5b, #bd362f); - background-image: linear-gradient(to bottom, #ee5f5b, #bd362f); - background-repeat: repeat-x; - border-color: #bd362f #bd362f #802420; - border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffbd362f', GradientType=0); - filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); -} - -.btn-danger:hover, -.btn-danger:active, -.btn-danger.active, -.btn-danger.disabled, -.btn-danger[disabled] { - color: #ffffff; - background-color: #bd362f; - *background-color: #a9302a; -} - -.btn-danger:active, -.btn-danger.active { - background-color: #942a25 \9; -} - -.btn-success { - color: #ffffff; - text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); - background-color: #5bb75b; - *background-color: #51a351; - background-image: -moz-linear-gradient(top, #62c462, #51a351); - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351)); - background-image: -webkit-linear-gradient(top, #62c462, #51a351); - background-image: -o-linear-gradient(top, #62c462, #51a351); - background-image: linear-gradient(to bottom, #62c462, #51a351); - background-repeat: repeat-x; - border-color: #51a351 #51a351 #387038; - border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff51a351', GradientType=0); - filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); -} - -.btn-success:hover, -.btn-success:active, -.btn-success.active, -.btn-success.disabled, -.btn-success[disabled] { - color: #ffffff; - background-color: #51a351; - *background-color: #499249; -} - -.btn-success:active, -.btn-success.active { - background-color: #408140 \9; -} - -.btn-info { - color: #ffffff; - text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); - background-color: #49afcd; - *background-color: #2f96b4; - background-image: -moz-linear-gradient(top, #5bc0de, #2f96b4); - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4)); - background-image: -webkit-linear-gradient(top, #5bc0de, #2f96b4); - background-image: -o-linear-gradient(top, #5bc0de, #2f96b4); - background-image: linear-gradient(to bottom, #5bc0de, #2f96b4); - background-repeat: repeat-x; - border-color: #2f96b4 #2f96b4 #1f6377; - border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2f96b4', GradientType=0); - filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); -} - -.btn-info:hover, -.btn-info:active, -.btn-info.active, -.btn-info.disabled, -.btn-info[disabled] { - color: #ffffff; - background-color: #2f96b4; - *background-color: #2a85a0; -} - -.btn-info:active, -.btn-info.active { - background-color: #24748c \9; -} - -.btn-inverse { - color: #ffffff; - text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); - background-color: #363636; - *background-color: #222222; - background-image: -moz-linear-gradient(top, #444444, #222222); - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#444444), to(#222222)); - background-image: -webkit-linear-gradient(top, #444444, #222222); - background-image: -o-linear-gradient(top, #444444, #222222); - background-image: linear-gradient(to bottom, #444444, #222222); - background-repeat: repeat-x; - border-color: #222222 #222222 #000000; - border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff444444', endColorstr='#ff222222', GradientType=0); - filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); -} - -.btn-inverse:hover, -.btn-inverse:active, -.btn-inverse.active, -.btn-inverse.disabled, -.btn-inverse[disabled] { - color: #ffffff; - background-color: #222222; - *background-color: #151515; -} - -.btn-inverse:active, -.btn-inverse.active { - background-color: #080808 \9; -} - -button.btn, -input[type="submit"].btn { - *padding-top: 3px; - *padding-bottom: 3px; -} - -button.btn::-moz-focus-inner, -input[type="submit"].btn::-moz-focus-inner { - padding: 0; - border: 0; -} - -button.btn.btn-large, -input[type="submit"].btn.btn-large { - *padding-top: 7px; - *padding-bottom: 7px; -} - -button.btn.btn-small, -input[type="submit"].btn.btn-small { - *padding-top: 3px; - *padding-bottom: 3px; -} - -button.btn.btn-mini, -input[type="submit"].btn.btn-mini { - *padding-top: 1px; - *padding-bottom: 1px; -} - -.btn-link, -.btn-link:active, -.btn-link[disabled] { - background-color: transparent; - background-image: none; - -webkit-box-shadow: none; - -moz-box-shadow: none; - box-shadow: none; -} - -.btn-link { - color: #0088cc; - cursor: pointer; - border-color: transparent; - -webkit-border-radius: 0; - -moz-border-radius: 0; - border-radius: 0; -} - -.btn-link:hover { - color: #005580; - text-decoration: underline; - background-color: transparent; -} - -.btn-link[disabled]:hover { - color: #333333; - text-decoration: none; -} - -.btn-group { - position: relative; - display: inline-block; - *display: inline; - *margin-left: .3em; - font-size: 0; - white-space: nowrap; - vertical-align: middle; - *zoom: 1; -} - -.btn-group:first-child { - *margin-left: 0; -} - -.btn-group + .btn-group { - margin-left: 5px; -} - -.btn-toolbar { - margin-top: 10px; - margin-bottom: 10px; - font-size: 0; -} - -.btn-toolbar > .btn + .btn, -.btn-toolbar > .btn-group + .btn, -.btn-toolbar > .btn + .btn-group { - margin-left: 5px; -} - -.btn-group > .btn { - position: relative; - -webkit-border-radius: 0; - -moz-border-radius: 0; - border-radius: 0; -} - -.btn-group > .btn + .btn { - margin-left: -1px; -} - -.btn-group > .btn, -.btn-group > .dropdown-menu, -.btn-group > .popover { - font-size: 14px; -} - -.btn-group > .btn-mini { - font-size: 10.5px; -} - -.btn-group > .btn-small { - font-size: 11.9px; -} - -.btn-group > .btn-large { - font-size: 17.5px; -} - -.btn-group > .btn:first-child { - margin-left: 0; - -webkit-border-bottom-left-radius: 4px; - border-bottom-left-radius: 4px; - -webkit-border-top-left-radius: 4px; - border-top-left-radius: 4px; - -moz-border-radius-bottomleft: 4px; - -moz-border-radius-topleft: 4px; -} - -.btn-group > .btn:last-child, -.btn-group > .dropdown-toggle { - -webkit-border-top-right-radius: 4px; - border-top-right-radius: 4px; - -webkit-border-bottom-right-radius: 4px; - border-bottom-right-radius: 4px; - -moz-border-radius-topright: 4px; - -moz-border-radius-bottomright: 4px; -} - -.btn-group > .btn.large:first-child { - margin-left: 0; - -webkit-border-bottom-left-radius: 6px; - border-bottom-left-radius: 6px; - -webkit-border-top-left-radius: 6px; - border-top-left-radius: 6px; - -moz-border-radius-bottomleft: 6px; - -moz-border-radius-topleft: 6px; -} - -.btn-group > .btn.large:last-child, -.btn-group > .large.dropdown-toggle { - -webkit-border-top-right-radius: 6px; - border-top-right-radius: 6px; - -webkit-border-bottom-right-radius: 6px; - border-bottom-right-radius: 6px; - -moz-border-radius-topright: 6px; - -moz-border-radius-bottomright: 6px; -} - -.btn-group > .btn:hover, -.btn-group > .btn:focus, -.btn-group > .btn:active, -.btn-group > .btn.active { - z-index: 2; -} - -.btn-group .dropdown-toggle:active, -.btn-group.open .dropdown-toggle { - outline: 0; -} - -.btn-group > .btn + .dropdown-toggle { - *padding-top: 5px; - padding-right: 8px; - *padding-bottom: 5px; - padding-left: 8px; - -webkit-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); - -moz-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); - box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); -} - -.btn-group > .btn-mini + .dropdown-toggle { - *padding-top: 2px; - padding-right: 5px; - *padding-bottom: 2px; - padding-left: 5px; -} - -.btn-group > .btn-small + .dropdown-toggle { - *padding-top: 5px; - *padding-bottom: 4px; -} - -.btn-group > .btn-large + .dropdown-toggle { - *padding-top: 7px; - padding-right: 12px; - *padding-bottom: 7px; - padding-left: 12px; -} - -.btn-group.open .dropdown-toggle { - background-image: none; - -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); - -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); - box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); -} - -.btn-group.open .btn.dropdown-toggle { - background-color: #e6e6e6; -} - -.btn-group.open .btn-primary.dropdown-toggle { - background-color: #0044cc; -} - -.btn-group.open .btn-warning.dropdown-toggle { - background-color: #f89406; -} - -.btn-group.open .btn-danger.dropdown-toggle { - background-color: #bd362f; -} - -.btn-group.open .btn-success.dropdown-toggle { - background-color: #51a351; -} - -.btn-group.open .btn-info.dropdown-toggle { - background-color: #2f96b4; -} - -.btn-group.open .btn-inverse.dropdown-toggle { - background-color: #222222; -} - -.btn .caret { - margin-top: 8px; - margin-left: 0; -} - -.btn-mini .caret, -.btn-small .caret, -.btn-large .caret { - margin-top: 6px; -} - -.btn-large .caret { - border-top-width: 5px; - border-right-width: 5px; - border-left-width: 5px; -} - -.dropup .btn-large .caret { - border-bottom-width: 5px; -} - -.btn-primary .caret, -.btn-warning .caret, -.btn-danger .caret, -.btn-info .caret, -.btn-success .caret, -.btn-inverse .caret { - border-top-color: #ffffff; - border-bottom-color: #ffffff; -} - -.btn-group-vertical { - display: inline-block; - *display: inline; - /* IE7 inline-block hack */ - - *zoom: 1; -} - -.btn-group-vertical > .btn { - display: block; - float: none; - max-width: 100%; - -webkit-border-radius: 0; - -moz-border-radius: 0; - border-radius: 0; -} - -.btn-group-vertical > .btn + .btn { - margin-top: -1px; - margin-left: 0; -} - -.btn-group-vertical > .btn:first-child { - -webkit-border-radius: 4px 4px 0 0; - -moz-border-radius: 4px 4px 0 0; - border-radius: 4px 4px 0 0; -} - -.btn-group-vertical > .btn:last-child { - -webkit-border-radius: 0 0 4px 4px; - -moz-border-radius: 0 0 4px 4px; - border-radius: 0 0 4px 4px; -} - -.btn-group-vertical > .btn-large:first-child { - -webkit-border-radius: 6px 6px 0 0; - -moz-border-radius: 6px 6px 0 0; - border-radius: 6px 6px 0 0; -} - -.btn-group-vertical > .btn-large:last-child { - -webkit-border-radius: 0 0 6px 6px; - -moz-border-radius: 0 0 6px 6px; - border-radius: 0 0 6px 6px; -} - -.alert { - padding: 8px 35px 8px 14px; - margin-bottom: 20px; - text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); - background-color: #fcf8e3; - border: 1px solid #fbeed5; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; -} - -.alert, -.alert h4 { - color: #c09853; -} - -.alert h4 { - margin: 0; -} - -.alert .close { - position: relative; - top: -2px; - right: -21px; - line-height: 20px; -} - -.alert-success { - color: #468847; - background-color: #dff0d8; - border-color: #d6e9c6; -} - -.alert-success h4 { - color: #468847; -} - -.alert-danger, -.alert-error { - color: #b94a48; - background-color: #f2dede; - border-color: #eed3d7; -} - -.alert-danger h4, -.alert-error h4 { - color: #b94a48; -} - -.alert-info { - color: #3a87ad; - background-color: #d9edf7; - border-color: #bce8f1; -} - -.alert-info h4 { - color: #3a87ad; -} - -.alert-block { - padding-top: 14px; - padding-bottom: 14px; -} - -.alert-block > p, -.alert-block > ul { - margin-bottom: 0; -} - -.alert-block p + p { - margin-top: 5px; -} - -.nav { - margin-bottom: 20px; - margin-left: 0; - list-style: none; -} - -.nav > li > a { - display: block; -} - -.nav > li > a:hover { - text-decoration: none; - background-color: #eeeeee; -} - -.nav > li > a > img { - max-width: none; -} - -.nav > .pull-right { - float: right; -} - -.nav-header { - display: block; - padding: 3px 15px; - font-size: 11px; - font-weight: bold; - line-height: 20px; - color: #999999; - text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); - text-transform: uppercase; -} - -.nav li + .nav-header { - margin-top: 9px; -} - -.nav-list { - padding-right: 15px; - padding-left: 15px; - margin-bottom: 0; -} - -.nav-list > li > a, -.nav-list .nav-header { - margin-right: -15px; - margin-left: -15px; - text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); -} - -.nav-list > li > a { - padding: 3px 15px; -} - -.nav-list > .active > a, -.nav-list > .active > a:hover { - color: #ffffff; - text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2); - background-color: #0088cc; -} - -.nav-list [class^="icon-"], -.nav-list [class*=" icon-"] { - margin-right: 2px; -} - -.nav-list .divider { - *width: 100%; - height: 1px; - margin: 9px 1px; - *margin: -5px 0 5px; - overflow: hidden; - background-color: #e5e5e5; - border-bottom: 1px solid #ffffff; -} - -.nav-tabs, -.nav-pills { - *zoom: 1; -} - -.nav-tabs:before, -.nav-pills:before, -.nav-tabs:after, -.nav-pills:after { - display: table; - line-height: 0; - content: ""; -} - -.nav-tabs:after, -.nav-pills:after { - clear: both; -} - -.nav-tabs > li, -.nav-pills > li { - float: left; -} - -.nav-tabs > li > a, -.nav-pills > li > a { - padding-right: 12px; - padding-left: 12px; - margin-right: 2px; - line-height: 14px; -} - -.nav-tabs { - border-bottom: 1px solid #ddd; -} - -.nav-tabs > li { - margin-bottom: -1px; -} - -.nav-tabs > li > a { - padding-top: 8px; - padding-bottom: 8px; - line-height: 20px; - border: 1px solid transparent; - -webkit-border-radius: 4px 4px 0 0; - -moz-border-radius: 4px 4px 0 0; - border-radius: 4px 4px 0 0; -} - -.nav-tabs > li > a:hover { - border-color: #eeeeee #eeeeee #dddddd; -} - -.nav-tabs > .active > a, -.nav-tabs > .active > a:hover { - color: #555555; - cursor: default; - background-color: #ffffff; - border: 1px solid #ddd; - border-bottom-color: transparent; -} - -.nav-pills > li > a { - padding-top: 8px; - padding-bottom: 8px; - margin-top: 2px; - margin-bottom: 2px; - -webkit-border-radius: 5px; - -moz-border-radius: 5px; - border-radius: 5px; -} - -.nav-pills > .active > a, -.nav-pills > .active > a:hover { - color: #ffffff; - background-color: #0088cc; -} - -.nav-stacked > li { - float: none; -} - -.nav-stacked > li > a { - margin-right: 0; -} - -.nav-tabs.nav-stacked { - border-bottom: 0; -} - -.nav-tabs.nav-stacked > li > a { - border: 1px solid #ddd; - -webkit-border-radius: 0; - -moz-border-radius: 0; - border-radius: 0; -} - -.nav-tabs.nav-stacked > li:first-child > a { - -webkit-border-top-right-radius: 4px; - border-top-right-radius: 4px; - -webkit-border-top-left-radius: 4px; - border-top-left-radius: 4px; - -moz-border-radius-topright: 4px; - -moz-border-radius-topleft: 4px; -} - -.nav-tabs.nav-stacked > li:last-child > a { - -webkit-border-bottom-right-radius: 4px; - border-bottom-right-radius: 4px; - -webkit-border-bottom-left-radius: 4px; - border-bottom-left-radius: 4px; - -moz-border-radius-bottomright: 4px; - -moz-border-radius-bottomleft: 4px; -} - -.nav-tabs.nav-stacked > li > a:hover { - z-index: 2; - border-color: #ddd; -} - -.nav-pills.nav-stacked > li > a { - margin-bottom: 3px; -} - -.nav-pills.nav-stacked > li:last-child > a { - margin-bottom: 1px; -} - -.nav-tabs .dropdown-menu { - -webkit-border-radius: 0 0 6px 6px; - -moz-border-radius: 0 0 6px 6px; - border-radius: 0 0 6px 6px; -} - -.nav-pills .dropdown-menu { - -webkit-border-radius: 6px; - -moz-border-radius: 6px; - border-radius: 6px; -} - -.nav .dropdown-toggle .caret { - margin-top: 6px; - border-top-color: #0088cc; - border-bottom-color: #0088cc; -} - -.nav .dropdown-toggle:hover .caret { - border-top-color: #005580; - border-bottom-color: #005580; -} - -/* move down carets for tabs */ - -.nav-tabs .dropdown-toggle .caret { - margin-top: 8px; -} - -.nav .active .dropdown-toggle .caret { - border-top-color: #fff; - border-bottom-color: #fff; -} - -.nav-tabs .active .dropdown-toggle .caret { - border-top-color: #555555; - border-bottom-color: #555555; -} - -.nav > .dropdown.active > a:hover { - cursor: pointer; -} - -.nav-tabs .open .dropdown-toggle, -.nav-pills .open .dropdown-toggle, -.nav > li.dropdown.open.active > a:hover { - color: #ffffff; - background-color: #999999; - border-color: #999999; -} - -.nav li.dropdown.open .caret, -.nav li.dropdown.open.active .caret, -.nav li.dropdown.open a:hover .caret { - border-top-color: #ffffff; - border-bottom-color: #ffffff; - opacity: 1; - filter: alpha(opacity=100); -} - -.tabs-stacked .open > a:hover { - border-color: #999999; -} - -.tabbable { - *zoom: 1; -} - -.tabbable:before, -.tabbable:after { - display: table; - line-height: 0; - content: ""; -} - -.tabbable:after { - clear: both; -} - -.tab-content { - overflow: auto; -} - -.tabs-below > .nav-tabs, -.tabs-right > .nav-tabs, -.tabs-left > .nav-tabs { - border-bottom: 0; -} - -.tab-content > .tab-pane, -.pill-content > .pill-pane { - display: none; -} - -.tab-content > .active, -.pill-content > .active { - display: block; -} - -.tabs-below > .nav-tabs { - border-top: 1px solid #ddd; -} - -.tabs-below > .nav-tabs > li { - margin-top: -1px; - margin-bottom: 0; -} - -.tabs-below > .nav-tabs > li > a { - -webkit-border-radius: 0 0 4px 4px; - -moz-border-radius: 0 0 4px 4px; - border-radius: 0 0 4px 4px; -} - -.tabs-below > .nav-tabs > li > a:hover { - border-top-color: #ddd; - border-bottom-color: transparent; -} - -.tabs-below > .nav-tabs > .active > a, -.tabs-below > .nav-tabs > .active > a:hover { - border-color: transparent #ddd #ddd #ddd; -} - -.tabs-left > .nav-tabs > li, -.tabs-right > .nav-tabs > li { - float: none; -} - -.tabs-left > .nav-tabs > li > a, -.tabs-right > .nav-tabs > li > a { - min-width: 74px; - margin-right: 0; - margin-bottom: 3px; -} - -.tabs-left > .nav-tabs { - float: left; - margin-right: 19px; - border-right: 1px solid #ddd; -} - -.tabs-left > .nav-tabs > li > a { - margin-right: -1px; - -webkit-border-radius: 4px 0 0 4px; - -moz-border-radius: 4px 0 0 4px; - border-radius: 4px 0 0 4px; -} - -.tabs-left > .nav-tabs > li > a:hover { - border-color: #eeeeee #dddddd #eeeeee #eeeeee; -} - -.tabs-left > .nav-tabs .active > a, -.tabs-left > .nav-tabs .active > a:hover { - border-color: #ddd transparent #ddd #ddd; - *border-right-color: #ffffff; -} - -.tabs-right > .nav-tabs { - float: right; - margin-left: 19px; - border-left: 1px solid #ddd; -} - -.tabs-right > .nav-tabs > li > a { - margin-left: -1px; - -webkit-border-radius: 0 4px 4px 0; - -moz-border-radius: 0 4px 4px 0; - border-radius: 0 4px 4px 0; -} - -.tabs-right > .nav-tabs > li > a:hover { - border-color: #eeeeee #eeeeee #eeeeee #dddddd; -} - -.tabs-right > .nav-tabs .active > a, -.tabs-right > .nav-tabs .active > a:hover { - border-color: #ddd #ddd #ddd transparent; - *border-left-color: #ffffff; -} - -.nav > .disabled > a { - color: #999999; -} - -.nav > .disabled > a:hover { - text-decoration: none; - cursor: default; - background-color: transparent; -} - -.navbar { - *position: relative; - *z-index: 2; - margin-bottom: 20px; - overflow: visible; -} - -.navbar-inner { - min-height: 40px; - padding-right: 20px; - padding-left: 20px; - background-color: #fafafa; - background-image: -moz-linear-gradient(top, #ffffff, #f2f2f2); - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f2f2f2)); - background-image: -webkit-linear-gradient(top, #ffffff, #f2f2f2); - background-image: -o-linear-gradient(top, #ffffff, #f2f2f2); - background-image: linear-gradient(to bottom, #ffffff, #f2f2f2); - background-repeat: repeat-x; - border: 1px solid #d4d4d4; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff2f2f2', GradientType=0); - *zoom: 1; - -webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065); - -moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065); - box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065); -} - -.navbar-inner:before, -.navbar-inner:after { - display: table; - line-height: 0; - content: ""; -} - -.navbar-inner:after { - clear: both; -} - -.navbar .container { - width: auto; -} - -.nav-collapse.collapse { - height: auto; - overflow: visible; -} - -.navbar .brand { - display: block; - float: left; - padding: 10px 20px 10px; - margin-left: -20px; - font-size: 20px; - font-weight: 200; - color: #777777; - text-shadow: 0 1px 0 #ffffff; -} - -.navbar .brand:hover { - text-decoration: none; -} - -.navbar-text { - margin-bottom: 0; - line-height: 40px; - color: #777777; -} - -.navbar-link { - color: #777777; -} - -.navbar-link:hover { - color: #333333; -} - -.navbar .divider-vertical { - height: 40px; - margin: 0 9px; - border-right: 1px solid #ffffff; - border-left: 1px solid #f2f2f2; -} - -.navbar .btn, -.navbar .btn-group { - margin-top: 5px; -} - -.navbar .btn-group .btn, -.navbar .input-prepend .btn, -.navbar .input-append .btn { - margin-top: 0; -} - -.navbar-form { - margin-bottom: 0; - *zoom: 1; -} - -.navbar-form:before, -.navbar-form:after { - display: table; - line-height: 0; - content: ""; -} - -.navbar-form:after { - clear: both; -} - -.navbar-form input, -.navbar-form select, -.navbar-form .radio, -.navbar-form .checkbox { - margin-top: 5px; -} - -.navbar-form input, -.navbar-form select, -.navbar-form .btn { - display: inline-block; - margin-bottom: 0; -} - -.navbar-form input[type="image"], -.navbar-form input[type="checkbox"], -.navbar-form input[type="radio"] { - margin-top: 3px; -} - -.navbar-form .input-append, -.navbar-form .input-prepend { - margin-top: 5px; - white-space: nowrap; -} - -.navbar-form .input-append input, -.navbar-form .input-prepend input { - margin-top: 0; -} - -.navbar-search { - position: relative; - float: left; - margin-top: 5px; - margin-bottom: 0; -} - -.navbar-search .search-query { - padding: 4px 14px; - margin-bottom: 0; - font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; - font-size: 13px; - font-weight: normal; - line-height: 1; - -webkit-border-radius: 15px; - -moz-border-radius: 15px; - border-radius: 15px; -} - -.navbar-static-top { - position: static; - margin-bottom: 0; -} - -.navbar-static-top .navbar-inner { - -webkit-border-radius: 0; - -moz-border-radius: 0; - border-radius: 0; -} - -.navbar-fixed-top, -.navbar-fixed-bottom { - position: fixed; - right: 0; - left: 0; - z-index: 1030; - margin-bottom: 0; -} - -.navbar-fixed-top .navbar-inner, -.navbar-static-top .navbar-inner { - border-width: 0 0 1px; -} - -.navbar-fixed-bottom .navbar-inner { - border-width: 1px 0 0; -} - -.navbar-fixed-top .navbar-inner, -.navbar-fixed-bottom .navbar-inner { - padding-right: 0; - padding-left: 0; - -webkit-border-radius: 0; - -moz-border-radius: 0; - border-radius: 0; -} - -.navbar-static-top .container, -.navbar-fixed-top .container, -.navbar-fixed-bottom .container { - width: 940px; -} - -.navbar-fixed-top { - top: 0; -} - -.navbar-fixed-top .navbar-inner, -.navbar-static-top .navbar-inner { - -webkit-box-shadow: 0 1px 10px rgba(0, 0, 0, 0.1); - -moz-box-shadow: 0 1px 10px rgba(0, 0, 0, 0.1); - box-shadow: 0 1px 10px rgba(0, 0, 0, 0.1); -} - -.navbar-fixed-bottom { - bottom: 0; -} - -.navbar-fixed-bottom .navbar-inner { - -webkit-box-shadow: 0 -1px 10px rgba(0, 0, 0, 0.1); - -moz-box-shadow: 0 -1px 10px rgba(0, 0, 0, 0.1); - box-shadow: 0 -1px 10px rgba(0, 0, 0, 0.1); -} - -.navbar .nav { - position: relative; - left: 0; - display: block; - float: left; - margin: 0 10px 0 0; -} - -.navbar .nav.pull-right { - float: right; - margin-right: 0; -} - -.navbar .nav > li { - float: left; -} - -.navbar .nav > li > a { - float: none; - padding: 10px 15px 10px; - color: #777777; - text-decoration: none; - text-shadow: 0 1px 0 #ffffff; -} - -.navbar .nav .dropdown-toggle .caret { - margin-top: 8px; -} - -.navbar .nav > li > a:focus, -.navbar .nav > li > a:hover { - color: #333333; - text-decoration: none; - background-color: transparent; -} - -.navbar .nav > .active > a, -.navbar .nav > .active > a:hover, -.navbar .nav > .active > a:focus { - color: #555555; - text-decoration: none; - background-color: #e5e5e5; - -webkit-box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.125); - -moz-box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.125); - box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.125); -} - -.navbar .btn-navbar { - display: none; - float: right; - padding: 7px 10px; - margin-right: 5px; - margin-left: 5px; - color: #ffffff; - text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); - background-color: #ededed; - *background-color: #e5e5e5; - background-image: -moz-linear-gradient(top, #f2f2f2, #e5e5e5); - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f2f2f2), to(#e5e5e5)); - background-image: -webkit-linear-gradient(top, #f2f2f2, #e5e5e5); - background-image: -o-linear-gradient(top, #f2f2f2, #e5e5e5); - background-image: linear-gradient(to bottom, #f2f2f2, #e5e5e5); - background-repeat: repeat-x; - border-color: #e5e5e5 #e5e5e5 #bfbfbf; - border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2f2f2', endColorstr='#ffe5e5e5', GradientType=0); - filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); - -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); - -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); - box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); -} - -.navbar .btn-navbar:hover, -.navbar .btn-navbar:active, -.navbar .btn-navbar.active, -.navbar .btn-navbar.disabled, -.navbar .btn-navbar[disabled] { - color: #ffffff; - background-color: #e5e5e5; - *background-color: #d9d9d9; -} - -.navbar .btn-navbar:active, -.navbar .btn-navbar.active { - background-color: #cccccc \9; -} - -.navbar .btn-navbar .icon-bar { - display: block; - width: 18px; - height: 2px; - background-color: #f5f5f5; - -webkit-border-radius: 1px; - -moz-border-radius: 1px; - border-radius: 1px; - -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); - -moz-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); - box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); -} - -.btn-navbar .icon-bar + .icon-bar { - margin-top: 3px; -} - -.navbar .nav > li > .dropdown-menu:before { - position: absolute; - top: -7px; - left: 9px; - display: inline-block; - border-right: 7px solid transparent; - border-bottom: 7px solid #ccc; - border-left: 7px solid transparent; - border-bottom-color: rgba(0, 0, 0, 0.2); - content: ''; -} - -.navbar .nav > li > .dropdown-menu:after { - position: absolute; - top: -6px; - left: 10px; - display: inline-block; - border-right: 6px solid transparent; - border-bottom: 6px solid #ffffff; - border-left: 6px solid transparent; - content: ''; -} - -.navbar-fixed-bottom .nav > li > .dropdown-menu:before { - top: auto; - bottom: -7px; - border-top: 7px solid #ccc; - border-bottom: 0; - border-top-color: rgba(0, 0, 0, 0.2); -} - -.navbar-fixed-bottom .nav > li > .dropdown-menu:after { - top: auto; - bottom: -6px; - border-top: 6px solid #ffffff; - border-bottom: 0; -} - -.navbar .nav li.dropdown > a:hover .caret { - border-top-color: #555555; - border-bottom-color: #555555; -} - -.navbar .nav li.dropdown.open > .dropdown-toggle, -.navbar .nav li.dropdown.active > .dropdown-toggle, -.navbar .nav li.dropdown.open.active > .dropdown-toggle { - color: #555555; - background-color: #e5e5e5; -} - -.navbar .nav li.dropdown > .dropdown-toggle .caret { - border-top-color: #777777; - border-bottom-color: #777777; -} - -.navbar .nav li.dropdown.open > .dropdown-toggle .caret, -.navbar .nav li.dropdown.active > .dropdown-toggle .caret, -.navbar .nav li.dropdown.open.active > .dropdown-toggle .caret { - border-top-color: #555555; - border-bottom-color: #555555; -} - -.navbar .pull-right > li > .dropdown-menu, -.navbar .nav > li > .dropdown-menu.pull-right { - right: 0; - left: auto; -} - -.navbar .pull-right > li > .dropdown-menu:before, -.navbar .nav > li > .dropdown-menu.pull-right:before { - right: 12px; - left: auto; -} - -.navbar .pull-right > li > .dropdown-menu:after, -.navbar .nav > li > .dropdown-menu.pull-right:after { - right: 13px; - left: auto; -} - -.navbar .pull-right > li > .dropdown-menu .dropdown-menu, -.navbar .nav > li > .dropdown-menu.pull-right .dropdown-menu { - right: 100%; - left: auto; - margin-right: -1px; - margin-left: 0; - -webkit-border-radius: 6px 0 6px 6px; - -moz-border-radius: 6px 0 6px 6px; - border-radius: 6px 0 6px 6px; -} - -.navbar-inverse .navbar-inner { - background-color: #1b1b1b; - background-image: -moz-linear-gradient(top, #222222, #111111); - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#222222), to(#111111)); - background-image: -webkit-linear-gradient(top, #222222, #111111); - background-image: -o-linear-gradient(top, #222222, #111111); - background-image: linear-gradient(to bottom, #222222, #111111); - background-repeat: repeat-x; - border-color: #252525; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff111111', GradientType=0); -} - -.navbar-inverse .brand, -.navbar-inverse .nav > li > a { - color: #999999; - text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); -} - -.navbar-inverse .brand:hover, -.navbar-inverse .nav > li > a:hover { - color: #ffffff; -} - -.navbar-inverse .brand { - color: #999999; -} - -.navbar-inverse .navbar-text { - color: #999999; -} - -.navbar-inverse .nav > li > a:focus, -.navbar-inverse .nav > li > a:hover { - color: #ffffff; - background-color: transparent; -} - -.navbar-inverse .nav .active > a, -.navbar-inverse .nav .active > a:hover, -.navbar-inverse .nav .active > a:focus { - color: #ffffff; - background-color: #111111; -} - -.navbar-inverse .navbar-link { - color: #999999; -} - -.navbar-inverse .navbar-link:hover { - color: #ffffff; -} - -.navbar-inverse .divider-vertical { - border-right-color: #222222; - border-left-color: #111111; -} - -.navbar-inverse .nav li.dropdown.open > .dropdown-toggle, -.navbar-inverse .nav li.dropdown.active > .dropdown-toggle, -.navbar-inverse .nav li.dropdown.open.active > .dropdown-toggle { - color: #ffffff; - background-color: #111111; -} - -.navbar-inverse .nav li.dropdown > a:hover .caret { - border-top-color: #ffffff; - border-bottom-color: #ffffff; -} - -.navbar-inverse .nav li.dropdown > .dropdown-toggle .caret { - border-top-color: #999999; - border-bottom-color: #999999; -} - -.navbar-inverse .nav li.dropdown.open > .dropdown-toggle .caret, -.navbar-inverse .nav li.dropdown.active > .dropdown-toggle .caret, -.navbar-inverse .nav li.dropdown.open.active > .dropdown-toggle .caret { - border-top-color: #ffffff; - border-bottom-color: #ffffff; -} - -.navbar-inverse .navbar-search .search-query { - color: #ffffff; - background-color: #515151; - border-color: #111111; - -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15); - -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15); - box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15); - -webkit-transition: none; - -moz-transition: none; - -o-transition: none; - transition: none; -} - -.navbar-inverse .navbar-search .search-query:-moz-placeholder { - color: #cccccc; -} - -.navbar-inverse .navbar-search .search-query:-ms-input-placeholder { - color: #cccccc; -} - -.navbar-inverse .navbar-search .search-query::-webkit-input-placeholder { - color: #cccccc; -} - -.navbar-inverse .navbar-search .search-query:focus, -.navbar-inverse .navbar-search .search-query.focused { - padding: 5px 15px; - color: #333333; - text-shadow: 0 1px 0 #ffffff; - background-color: #ffffff; - border: 0; - outline: 0; - -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); - -moz-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); - box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); -} - -.navbar-inverse .btn-navbar { - color: #ffffff; - text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); - background-color: #0e0e0e; - *background-color: #040404; - background-image: -moz-linear-gradient(top, #151515, #040404); - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#151515), to(#040404)); - background-image: -webkit-linear-gradient(top, #151515, #040404); - background-image: -o-linear-gradient(top, #151515, #040404); - background-image: linear-gradient(to bottom, #151515, #040404); - background-repeat: repeat-x; - border-color: #040404 #040404 #000000; - border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff151515', endColorstr='#ff040404', GradientType=0); - filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); -} - -.navbar-inverse .btn-navbar:hover, -.navbar-inverse .btn-navbar:active, -.navbar-inverse .btn-navbar.active, -.navbar-inverse .btn-navbar.disabled, -.navbar-inverse .btn-navbar[disabled] { - color: #ffffff; - background-color: #040404; - *background-color: #000000; -} - -.navbar-inverse .btn-navbar:active, -.navbar-inverse .btn-navbar.active { - background-color: #000000 \9; -} - -.breadcrumb { - padding: 8px 15px; - margin: 0 0 20px; - list-style: none; - background-color: #f5f5f5; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; -} - -.breadcrumb > li { - display: inline-block; - *display: inline; - text-shadow: 0 1px 0 #ffffff; - *zoom: 1; -} - -.breadcrumb > li > .divider { - padding: 0 5px; - color: #ccc; -} - -.breadcrumb > .active { - color: #999999; -} - -.pagination { - margin: 20px 0; -} - -.pagination ul { - display: inline-block; - *display: inline; - margin-bottom: 0; - margin-left: 0; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; - *zoom: 1; - -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); - -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); - box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); -} - -.pagination ul > li { - display: inline; -} - -.pagination ul > li > a, -.pagination ul > li > span { - float: left; - padding: 4px 12px; - line-height: 20px; - text-decoration: none; - background-color: #ffffff; - border: 1px solid #dddddd; - border-left-width: 0; -} - -.pagination ul > li > a:hover, -.pagination ul > .active > a, -.pagination ul > .active > span { - background-color: #f5f5f5; -} - -.pagination ul > .active > a, -.pagination ul > .active > span { - color: #999999; - cursor: default; -} - -.pagination ul > .disabled > span, -.pagination ul > .disabled > a, -.pagination ul > .disabled > a:hover { - color: #999999; - cursor: default; - background-color: transparent; -} - -.pagination ul > li:first-child > a, -.pagination ul > li:first-child > span { - border-left-width: 1px; - -webkit-border-bottom-left-radius: 4px; - border-bottom-left-radius: 4px; - -webkit-border-top-left-radius: 4px; - border-top-left-radius: 4px; - -moz-border-radius-bottomleft: 4px; - -moz-border-radius-topleft: 4px; -} - -.pagination ul > li:last-child > a, -.pagination ul > li:last-child > span { - -webkit-border-top-right-radius: 4px; - border-top-right-radius: 4px; - -webkit-border-bottom-right-radius: 4px; - border-bottom-right-radius: 4px; - -moz-border-radius-topright: 4px; - -moz-border-radius-bottomright: 4px; -} - -.pagination-centered { - text-align: center; -} - -.pagination-right { - text-align: right; -} - -.pagination-large ul > li > a, -.pagination-large ul > li > span { - padding: 11px 19px; - font-size: 17.5px; -} - -.pagination-large ul > li:first-child > a, -.pagination-large ul > li:first-child > span { - -webkit-border-bottom-left-radius: 6px; - border-bottom-left-radius: 6px; - -webkit-border-top-left-radius: 6px; - border-top-left-radius: 6px; - -moz-border-radius-bottomleft: 6px; - -moz-border-radius-topleft: 6px; -} - -.pagination-large ul > li:last-child > a, -.pagination-large ul > li:last-child > span { - -webkit-border-top-right-radius: 6px; - border-top-right-radius: 6px; - -webkit-border-bottom-right-radius: 6px; - border-bottom-right-radius: 6px; - -moz-border-radius-topright: 6px; - -moz-border-radius-bottomright: 6px; -} - -.pagination-mini ul > li:first-child > a, -.pagination-small ul > li:first-child > a, -.pagination-mini ul > li:first-child > span, -.pagination-small ul > li:first-child > span { - -webkit-border-bottom-left-radius: 3px; - border-bottom-left-radius: 3px; - -webkit-border-top-left-radius: 3px; - border-top-left-radius: 3px; - -moz-border-radius-bottomleft: 3px; - -moz-border-radius-topleft: 3px; -} - -.pagination-mini ul > li:last-child > a, -.pagination-small ul > li:last-child > a, -.pagination-mini ul > li:last-child > span, -.pagination-small ul > li:last-child > span { - -webkit-border-top-right-radius: 3px; - border-top-right-radius: 3px; - -webkit-border-bottom-right-radius: 3px; - border-bottom-right-radius: 3px; - -moz-border-radius-topright: 3px; - -moz-border-radius-bottomright: 3px; -} - -.pagination-small ul > li > a, -.pagination-small ul > li > span { - padding: 2px 10px; - font-size: 11.9px; -} - -.pagination-mini ul > li > a, -.pagination-mini ul > li > span { - padding: 0 6px; - font-size: 10.5px; -} - -.pager { - margin: 20px 0; - text-align: center; - list-style: none; - *zoom: 1; -} - -.pager:before, -.pager:after { - display: table; - line-height: 0; - content: ""; -} - -.pager:after { - clear: both; -} - -.pager li { - display: inline; -} - -.pager li > a, -.pager li > span { - display: inline-block; - padding: 5px 14px; - background-color: #fff; - border: 1px solid #ddd; - -webkit-border-radius: 15px; - -moz-border-radius: 15px; - border-radius: 15px; -} - -.pager li > a:hover { - text-decoration: none; - background-color: #f5f5f5; -} - -.pager .next > a, -.pager .next > span { - float: right; -} - -.pager .previous > a, -.pager .previous > span { - float: left; -} - -.pager .disabled > a, -.pager .disabled > a:hover, -.pager .disabled > span { - color: #999999; - cursor: default; - background-color: #fff; -} - -.modal-backdrop { - position: fixed; - top: 0; - right: 0; - bottom: 0; - left: 0; - z-index: 1040; - background-color: #000000; -} - -.modal-backdrop.fade { - opacity: 0; -} - -.modal-backdrop, -.modal-backdrop.fade.in { - opacity: 0.8; - filter: alpha(opacity=80); -} - -.modal { - position: fixed; - top: 10%; - left: 50%; - z-index: 1050; - width: 560px; - margin-left: -280px; - background-color: #ffffff; - border: 1px solid #999; - border: 1px solid rgba(0, 0, 0, 0.3); - *border: 1px solid #999; - -webkit-border-radius: 6px; - -moz-border-radius: 6px; - border-radius: 6px; - outline: none; - -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); - -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); - box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); - -webkit-background-clip: padding-box; - -moz-background-clip: padding-box; - background-clip: padding-box; -} - -.modal.fade { - top: -25%; - -webkit-transition: opacity 0.3s linear, top 0.3s ease-out; - -moz-transition: opacity 0.3s linear, top 0.3s ease-out; - -o-transition: opacity 0.3s linear, top 0.3s ease-out; - transition: opacity 0.3s linear, top 0.3s ease-out; -} - -.modal.fade.in { - top: 10%; -} - -.modal-header { - padding: 9px 15px; - border-bottom: 1px solid #eee; -} - -.modal-header .close { - margin-top: 2px; -} - -.modal-header h3 { - margin: 0; - line-height: 30px; -} - -.modal-body { - position: relative; - max-height: 400px; - padding: 15px; - overflow-y: auto; -} - -.modal-form { - margin-bottom: 0; -} - -.modal-footer { - padding: 14px 15px 15px; - margin-bottom: 0; - text-align: right; - background-color: #f5f5f5; - border-top: 1px solid #ddd; - -webkit-border-radius: 0 0 6px 6px; - -moz-border-radius: 0 0 6px 6px; - border-radius: 0 0 6px 6px; - *zoom: 1; - -webkit-box-shadow: inset 0 1px 0 #ffffff; - -moz-box-shadow: inset 0 1px 0 #ffffff; - box-shadow: inset 0 1px 0 #ffffff; -} - -.modal-footer:before, -.modal-footer:after { - display: table; - line-height: 0; - content: ""; -} - -.modal-footer:after { - clear: both; -} - -.modal-footer .btn + .btn { - margin-bottom: 0; - margin-left: 5px; -} - -.modal-footer .btn-group .btn + .btn { - margin-left: -1px; -} - -.modal-footer .btn-block + .btn-block { - margin-left: 0; -} - -.tooltip { - position: absolute; - z-index: 1030; - display: block; - padding: 5px; - font-size: 11px; - opacity: 0; - filter: alpha(opacity=0); - visibility: visible; -} - -.tooltip.in { - opacity: 0.8; - filter: alpha(opacity=80); -} - -.tooltip.top { - margin-top: -3px; -} - -.tooltip.right { - margin-left: 3px; -} - -.tooltip.bottom { - margin-top: 3px; -} - -.tooltip.left { - margin-left: -3px; -} - -.tooltip-inner { - max-width: 200px; - padding: 3px 8px; - color: #ffffff; - text-align: center; - text-decoration: none; - background-color: #000000; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; -} - -.tooltip-arrow { - position: absolute; - width: 0; - height: 0; - border-color: transparent; - border-style: solid; -} - -.tooltip.top .tooltip-arrow { - bottom: 0; - left: 50%; - margin-left: -5px; - border-top-color: #000000; - border-width: 5px 5px 0; -} - -.tooltip.right .tooltip-arrow { - top: 50%; - left: 0; - margin-top: -5px; - border-right-color: #000000; - border-width: 5px 5px 5px 0; -} - -.tooltip.left .tooltip-arrow { - top: 50%; - right: 0; - margin-top: -5px; - border-left-color: #000000; - border-width: 5px 0 5px 5px; -} - -.tooltip.bottom .tooltip-arrow { - top: 0; - left: 50%; - margin-left: -5px; - border-bottom-color: #000000; - border-width: 0 5px 5px; -} - -.popover { - position: absolute; - top: 0; - left: 0; - z-index: 1010; - display: none; - width: 236px; - padding: 1px; - text-align: left; - white-space: normal; - background-color: #ffffff; - border: 1px solid #ccc; - border: 1px solid rgba(0, 0, 0, 0.2); - -webkit-border-radius: 6px; - -moz-border-radius: 6px; - border-radius: 6px; - -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); - -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); - box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); - -webkit-background-clip: padding-box; - -moz-background-clip: padding; - background-clip: padding-box; -} - -.popover.top { - margin-top: -10px; -} - -.popover.right { - margin-left: 10px; -} - -.popover.bottom { - margin-top: 10px; -} - -.popover.left { - margin-left: -10px; -} - -.popover-title { - padding: 8px 14px; - margin: 0; - font-size: 14px; - font-weight: normal; - line-height: 18px; - background-color: #f7f7f7; - border-bottom: 1px solid #ebebeb; - -webkit-border-radius: 5px 5px 0 0; - -moz-border-radius: 5px 5px 0 0; - border-radius: 5px 5px 0 0; -} - -.popover-content { - padding: 9px 14px; -} - -.popover .arrow, -.popover .arrow:after { - position: absolute; - display: block; - width: 0; - height: 0; - border-color: transparent; - border-style: solid; -} - -.popover .arrow { - border-width: 11px; -} - -.popover .arrow:after { - border-width: 10px; - content: ""; -} - -.popover.top .arrow { - bottom: -11px; - left: 50%; - margin-left: -11px; - border-top-color: #999; - border-top-color: rgba(0, 0, 0, 0.25); - border-bottom-width: 0; -} - -.popover.top .arrow:after { - bottom: 1px; - margin-left: -10px; - border-top-color: #ffffff; - border-bottom-width: 0; -} - -.popover.right .arrow { - top: 50%; - left: -11px; - margin-top: -11px; - border-right-color: #999; - border-right-color: rgba(0, 0, 0, 0.25); - border-left-width: 0; -} - -.popover.right .arrow:after { - bottom: -10px; - left: 1px; - border-right-color: #ffffff; - border-left-width: 0; -} - -.popover.bottom .arrow { - top: -11px; - left: 50%; - margin-left: -11px; - border-bottom-color: #999; - border-bottom-color: rgba(0, 0, 0, 0.25); - border-top-width: 0; -} - -.popover.bottom .arrow:after { - top: 1px; - margin-left: -10px; - border-bottom-color: #ffffff; - border-top-width: 0; -} - -.popover.left .arrow { - top: 50%; - right: -11px; - margin-top: -11px; - border-left-color: #999; - border-left-color: rgba(0, 0, 0, 0.25); - border-right-width: 0; -} - -.popover.left .arrow:after { - right: 1px; - bottom: -10px; - border-left-color: #ffffff; - border-right-width: 0; -} - -.thumbnails { - margin-left: -20px; - list-style: none; - *zoom: 1; -} - -.thumbnails:before, -.thumbnails:after { - display: table; - line-height: 0; - content: ""; -} - -.thumbnails:after { - clear: both; -} - -.row-fluid .thumbnails { - margin-left: 0; -} - -.thumbnails > li { - float: left; - margin-bottom: 20px; - margin-left: 20px; -} - -.thumbnail { - display: block; - padding: 4px; - line-height: 20px; - border: 1px solid #ddd; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; - -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.055); - -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.055); - box-shadow: 0 1px 3px rgba(0, 0, 0, 0.055); - -webkit-transition: all 0.2s ease-in-out; - -moz-transition: all 0.2s ease-in-out; - -o-transition: all 0.2s ease-in-out; - transition: all 0.2s ease-in-out; -} - -a.thumbnail:hover { - border-color: #0088cc; - -webkit-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); - -moz-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); - box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); -} - -.thumbnail > img { - display: block; - max-width: 100%; - margin-right: auto; - margin-left: auto; -} - -.thumbnail .caption { - padding: 9px; - color: #555555; -} - -.media, -.media-body { - overflow: hidden; - *overflow: visible; - zoom: 1; -} - -.media, -.media .media { - margin-top: 15px; -} - -.media:first-child { - margin-top: 0; -} - -.media-object { - display: block; -} - -.media-heading { - margin: 0 0 5px; -} - -.media .pull-left { - margin-right: 10px; -} - -.media .pull-right { - margin-left: 10px; -} - -.media-list { - margin-left: 0; - list-style: none; -} - -.label, -.badge { - display: inline-block; - padding: 2px 4px; - font-size: 11.844px; - font-weight: bold; - line-height: 14px; - color: #ffffff; - text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); - white-space: nowrap; - vertical-align: baseline; - background-color: #999999; -} - -.label { - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - border-radius: 3px; -} - -.badge { - padding-right: 9px; - padding-left: 9px; - -webkit-border-radius: 9px; - -moz-border-radius: 9px; - border-radius: 9px; -} - -.label:empty, -.badge:empty { - display: none; -} - -a.label:hover, -a.badge:hover { - color: #ffffff; - text-decoration: none; - cursor: pointer; -} - -.label-important, -.badge-important { - background-color: #b94a48; -} - -.label-important[href], -.badge-important[href] { - background-color: #953b39; -} - -.label-warning, -.badge-warning { - background-color: #f89406; -} - -.label-warning[href], -.badge-warning[href] { - background-color: #c67605; -} - -.label-success, -.badge-success { - background-color: #468847; -} - -.label-success[href], -.badge-success[href] { - background-color: #356635; -} - -.label-info, -.badge-info { - background-color: #3a87ad; -} - -.label-info[href], -.badge-info[href] { - background-color: #2d6987; -} - -.label-inverse, -.badge-inverse { - background-color: #333333; -} - -.label-inverse[href], -.badge-inverse[href] { - background-color: #1a1a1a; -} - -.btn .label, -.btn .badge { - position: relative; - top: -1px; -} - -.btn-mini .label, -.btn-mini .badge { - top: 0; -} - -@-webkit-keyframes progress-bar-stripes { - from { - background-position: 40px 0; - } - to { - background-position: 0 0; - } -} - -@-moz-keyframes progress-bar-stripes { - from { - background-position: 40px 0; - } - to { - background-position: 0 0; - } -} - -@-ms-keyframes progress-bar-stripes { - from { - background-position: 40px 0; - } - to { - background-position: 0 0; - } -} - -@-o-keyframes progress-bar-stripes { - from { - background-position: 0 0; - } - to { - background-position: 40px 0; - } -} - -@keyframes progress-bar-stripes { - from { - background-position: 40px 0; - } - to { - background-position: 0 0; - } -} - -.progress { - height: 20px; - margin-bottom: 20px; - overflow: hidden; - background-color: #f7f7f7; - background-image: -moz-linear-gradient(top, #f5f5f5, #f9f9f9); - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9)); - background-image: -webkit-linear-gradient(top, #f5f5f5, #f9f9f9); - background-image: -o-linear-gradient(top, #f5f5f5, #f9f9f9); - background-image: linear-gradient(to bottom, #f5f5f5, #f9f9f9); - background-repeat: repeat-x; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#fff9f9f9', GradientType=0); - -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); - -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); - box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); -} - -.progress .bar { - float: left; - width: 0; - height: 100%; - font-size: 12px; - color: #ffffff; - text-align: center; - text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); - background-color: #0e90d2; - background-image: -moz-linear-gradient(top, #149bdf, #0480be); - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be)); - background-image: -webkit-linear-gradient(top, #149bdf, #0480be); - background-image: -o-linear-gradient(top, #149bdf, #0480be); - background-image: linear-gradient(to bottom, #149bdf, #0480be); - background-repeat: repeat-x; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff149bdf', endColorstr='#ff0480be', GradientType=0); - -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); - -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); - box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - -webkit-transition: width 0.6s ease; - -moz-transition: width 0.6s ease; - -o-transition: width 0.6s ease; - transition: width 0.6s ease; -} - -.progress .bar + .bar { - -webkit-box-shadow: inset 1px 0 0 rgba(0, 0, 0, 0.15), inset 0 -1px 0 rgba(0, 0, 0, 0.15); - -moz-box-shadow: inset 1px 0 0 rgba(0, 0, 0, 0.15), inset 0 -1px 0 rgba(0, 0, 0, 0.15); - box-shadow: inset 1px 0 0 rgba(0, 0, 0, 0.15), inset 0 -1px 0 rgba(0, 0, 0, 0.15); -} - -.progress-striped .bar { - background-color: #149bdf; - background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); - background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); - background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); - background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); - background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); - -webkit-background-size: 40px 40px; - -moz-background-size: 40px 40px; - -o-background-size: 40px 40px; - background-size: 40px 40px; -} - -.progress.active .bar { - -webkit-animation: progress-bar-stripes 2s linear infinite; - -moz-animation: progress-bar-stripes 2s linear infinite; - -ms-animation: progress-bar-stripes 2s linear infinite; - -o-animation: progress-bar-stripes 2s linear infinite; - animation: progress-bar-stripes 2s linear infinite; -} - -.progress-danger .bar, -.progress .bar-danger { - background-color: #dd514c; - background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35); - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35)); - background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35); - background-image: -o-linear-gradient(top, #ee5f5b, #c43c35); - background-image: linear-gradient(to bottom, #ee5f5b, #c43c35); - background-repeat: repeat-x; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffc43c35', GradientType=0); -} - -.progress-danger.progress-striped .bar, -.progress-striped .bar-danger { - background-color: #ee5f5b; - background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); - background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); - background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); - background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); - background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); -} - -.progress-success .bar, -.progress .bar-success { - background-color: #5eb95e; - background-image: -moz-linear-gradient(top, #62c462, #57a957); - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957)); - background-image: -webkit-linear-gradient(top, #62c462, #57a957); - background-image: -o-linear-gradient(top, #62c462, #57a957); - background-image: linear-gradient(to bottom, #62c462, #57a957); - background-repeat: repeat-x; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff57a957', GradientType=0); -} - -.progress-success.progress-striped .bar, -.progress-striped .bar-success { - background-color: #62c462; - background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); - background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); - background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); - background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); - background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); -} - -.progress-info .bar, -.progress .bar-info { - background-color: #4bb1cf; - background-image: -moz-linear-gradient(top, #5bc0de, #339bb9); - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9)); - background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9); - background-image: -o-linear-gradient(top, #5bc0de, #339bb9); - background-image: linear-gradient(to bottom, #5bc0de, #339bb9); - background-repeat: repeat-x; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff339bb9', GradientType=0); -} - -.progress-info.progress-striped .bar, -.progress-striped .bar-info { - background-color: #5bc0de; - background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); - background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); - background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); - background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); - background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); -} - -.progress-warning .bar, -.progress .bar-warning { - background-color: #faa732; - background-image: -moz-linear-gradient(top, #fbb450, #f89406); - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406)); - background-image: -webkit-linear-gradient(top, #fbb450, #f89406); - background-image: -o-linear-gradient(top, #fbb450, #f89406); - background-image: linear-gradient(to bottom, #fbb450, #f89406); - background-repeat: repeat-x; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0); -} - -.progress-warning.progress-striped .bar, -.progress-striped .bar-warning { - background-color: #fbb450; - background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); - background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); - background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); - background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); - background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); -} - -.accordion { - margin-bottom: 20px; -} - -.accordion-group { - margin-bottom: 2px; - border: 1px solid #e5e5e5; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; -} - -.accordion-heading { - border-bottom: 0; -} - -.accordion-heading .accordion-toggle { - display: block; - padding: 8px 15px; -} - -.accordion-toggle { - cursor: pointer; -} - -.accordion-inner { - padding: 9px 15px; - border-top: 1px solid #e5e5e5; -} - -.carousel { - position: relative; - margin-bottom: 20px; - line-height: 1; -} - -.carousel-inner { - position: relative; - width: 100%; - overflow: hidden; -} - -.carousel-inner > .item { - position: relative; - display: none; - -webkit-transition: 0.6s ease-in-out left; - -moz-transition: 0.6s ease-in-out left; - -o-transition: 0.6s ease-in-out left; - transition: 0.6s ease-in-out left; -} - -.carousel-inner > .item > img { - display: block; - line-height: 1; -} - -.carousel-inner > .active, -.carousel-inner > .next, -.carousel-inner > .prev { - display: block; -} - -.carousel-inner > .active { - left: 0; -} - -.carousel-inner > .next, -.carousel-inner > .prev { - position: absolute; - top: 0; - width: 100%; -} - -.carousel-inner > .next { - left: 100%; -} - -.carousel-inner > .prev { - left: -100%; -} - -.carousel-inner > .next.left, -.carousel-inner > .prev.right { - left: 0; -} - -.carousel-inner > .active.left { - left: -100%; -} - -.carousel-inner > .active.right { - left: 100%; -} - -.carousel-control { - position: absolute; - top: 40%; - left: 15px; - width: 40px; - height: 40px; - margin-top: -20px; - font-size: 60px; - font-weight: 100; - line-height: 30px; - color: #ffffff; - text-align: center; - background: #222222; - border: 3px solid #ffffff; - -webkit-border-radius: 23px; - -moz-border-radius: 23px; - border-radius: 23px; - opacity: 0.5; - filter: alpha(opacity=50); -} - -.carousel-control.right { - right: 15px; - left: auto; -} - -.carousel-control:hover { - color: #ffffff; - text-decoration: none; - opacity: 0.9; - filter: alpha(opacity=90); -} - -.carousel-caption { - position: absolute; - right: 0; - bottom: 0; - left: 0; - padding: 15px; - background: #333333; - background: rgba(0, 0, 0, 0.75); -} - -.carousel-caption h4, -.carousel-caption p { - line-height: 20px; - color: #ffffff; -} - -.carousel-caption h4 { - margin: 0 0 5px; -} - -.carousel-caption p { - margin-bottom: 0; -} - -.hero-unit { - padding: 60px; - margin-bottom: 30px; - font-size: 18px; - font-weight: 200; - line-height: 30px; - color: inherit; - background-color: #eeeeee; - -webkit-border-radius: 6px; - -moz-border-radius: 6px; - border-radius: 6px; -} - -.hero-unit h1 { - margin-bottom: 0; - font-size: 60px; - line-height: 1; - letter-spacing: -1px; - color: inherit; -} - -.hero-unit li { - line-height: 30px; -} - -.pull-right { - float: right; -} - -.pull-left { - float: left; -} - -.hide { - display: none; -} - -.show { - display: block; -} - -.invisible { - visibility: hidden; -} - -.affix { - position: fixed; -} diff --git a/samples/boot/redis-json/src/main/resources/static/resources/img/favicon.ico b/samples/boot/redis-json/src/main/resources/static/resources/img/favicon.ico deleted file mode 100644 index bfb9974..0000000 Binary files a/samples/boot/redis-json/src/main/resources/static/resources/img/favicon.ico and /dev/null differ diff --git a/samples/boot/redis-json/src/main/resources/static/resources/img/logo.png b/samples/boot/redis-json/src/main/resources/static/resources/img/logo.png deleted file mode 100644 index 3932308..0000000 Binary files a/samples/boot/redis-json/src/main/resources/static/resources/img/logo.png and /dev/null differ diff --git a/samples/boot/redis-json/src/main/resources/templates/home.html b/samples/boot/redis-json/src/main/resources/templates/home.html deleted file mode 100644 index 78c74c3..0000000 --- a/samples/boot/redis-json/src/main/resources/templates/home.html +++ /dev/null @@ -1,37 +0,0 @@ - - - - - Home - - - - -
-
-
- Add value to session - - - -
-
-
-
- - - - - - - - - - - - - -
Attribute NameAttribute Value
-
- - \ No newline at end of file diff --git a/samples/boot/redis-json/src/main/resources/templates/layout.html b/samples/boot/redis-json/src/main/resources/templates/layout.html deleted file mode 100644 index 6dda233..0000000 --- a/samples/boot/redis-json/src/main/resources/templates/layout.html +++ /dev/null @@ -1,123 +0,0 @@ - - - - Spring Session Sample - - - - - - - - - - - -
- - -
-
-
-
- Some Success message -
-
- Fake content -
-
-
-
-
-
-
- -
-
- - \ No newline at end of file diff --git a/samples/boot/redis-json/src/main/resources/templates/login.html b/samples/boot/redis-json/src/main/resources/templates/login.html deleted file mode 100644 index 2faadfa..0000000 --- a/samples/boot/redis-json/src/main/resources/templates/login.html +++ /dev/null @@ -1,35 +0,0 @@ - - - - - Login - - -
-
-
- Please Login - -
Invalid - username and password.
-
You - have been logged out.
- - - -
- -
-
-
-
- -
-

- This demo use GenericJackson2JsonRedisSerializer as DefaultRedis Serializer. -
- To login use user as username and password as Password. -

-
- - \ No newline at end of file diff --git a/samples/boot/redis/README.adoc b/samples/boot/redis/README.adoc deleted file mode 100644 index d7203b5..0000000 --- a/samples/boot/redis/README.adoc +++ /dev/null @@ -1 +0,0 @@ -Demonstrates using Spring Session with Spring Boot and Spring Security. You can log in with the username "user" and the password "password". \ No newline at end of file diff --git a/samples/boot/redis/spring-session-sample-boot-redis.gradle b/samples/boot/redis/spring-session-sample-boot-redis.gradle deleted file mode 100644 index ec1c7a2..0000000 --- a/samples/boot/redis/spring-session-sample-boot-redis.gradle +++ /dev/null @@ -1,18 +0,0 @@ -apply plugin: 'io.spring.convention.spring-sample-boot' - -dependencies { - compile project(':spring-session-data-redis') - compile "io.lettuce:lettuce-core" - compile"org.springframework.boot:spring-boot-starter-security" - compile"org.springframework.boot:spring-boot-starter-thymeleaf" - compile"org.springframework.boot:spring-boot-starter-web" - compile"nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect" - compile"org.webjars:bootstrap" - compile"org.webjars:html5shiv" - compile"org.webjars:webjars-locator" - - testCompile "org.springframework.boot:spring-boot-starter-test" - - integrationTestCompile seleniumDependencies - -} diff --git a/samples/boot/redis/src/integration-test/java/sample/BootTests.java b/samples/boot/redis/src/integration-test/java/sample/BootTests.java deleted file mode 100644 index 0caa912..0000000 --- a/samples/boot/redis/src/integration-test/java/sample/BootTests.java +++ /dev/null @@ -1,81 +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.junit.runner.RunWith; -import org.openqa.selenium.WebDriver; -import sample.pages.HomePage; -import sample.pages.LoginPage; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.htmlunit.webdriver.MockMvcHtmlUnitDriverBuilder; - -/** - * @author Eddú Meléndez - */ -@RunWith(SpringRunner.class) -@AutoConfigureMockMvc -@SpringBootTest(webEnvironment = WebEnvironment.MOCK) -public class BootTests { - - @Autowired - private MockMvc mockMvc; - - private WebDriver driver; - - @Before - public void setup() { - this.driver = MockMvcHtmlUnitDriverBuilder.mockMvcSetup(this.mockMvc).build(); - } - - @After - public void tearDown() { - this.driver.quit(); - } - - @Test - public void home() { - LoginPage login = HomePage.go(this.driver); - login.assertAt(); - } - - @Test - public void login() { - LoginPage login = HomePage.go(this.driver); - HomePage home = login.form().login(HomePage.class); - home.assertAt(); - home.containCookie("SESSION"); - home.doesNotContainCookie("JSESSIONID"); - } - - @Test - public void logout() { - LoginPage login = HomePage.go(this.driver); - HomePage home = login.form().login(HomePage.class); - home.logout(); - login.assertAt(); - } - -} diff --git a/samples/boot/redis/src/integration-test/java/sample/pages/BasePage.java b/samples/boot/redis/src/integration-test/java/sample/pages/BasePage.java deleted file mode 100644 index 763c078..0000000 --- a/samples/boot/redis/src/integration-test/java/sample/pages/BasePage.java +++ /dev/null @@ -1,41 +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; - -/** - * @author Eddú Meléndez - */ -public 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"; - driver.get(baseUrl + get); - } - -} diff --git a/samples/boot/redis/src/integration-test/java/sample/pages/HomePage.java b/samples/boot/redis/src/integration-test/java/sample/pages/HomePage.java deleted file mode 100644 index a751fd2..0000000 --- a/samples/boot/redis/src/integration-test/java/sample/pages/HomePage.java +++ /dev/null @@ -1,63 +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 java.util.Set; - -import org.openqa.selenium.By; -import org.openqa.selenium.Cookie; -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 Eddú Meléndez - */ -public class HomePage extends BasePage { - - public HomePage(WebDriver driver) { - super(driver); - } - - public static LoginPage go(WebDriver driver) { - get(driver, "/"); - return PageFactory.initElements(driver, LoginPage.class); - } - - public void assertAt() { - assertThat(getDriver().getTitle()).isEqualTo("Spring Session Sample - Secured Content"); - } - - public void containCookie(String cookieName) { - Set cookies = getDriver().manage().getCookies(); - assertThat(cookies).extracting("name").contains(cookieName); - } - - public void doesNotContainCookie(String cookieName) { - Set cookies = getDriver().manage().getCookies(); - assertThat(cookies).extracting("name").doesNotContain(cookieName); - } - - public HomePage logout() { - WebElement logout = getDriver().findElement(By.cssSelector("input[type=\"submit\"]")); - logout.click(); - return PageFactory.initElements(getDriver(), HomePage.class); - } - -} diff --git a/samples/boot/redis/src/integration-test/java/sample/pages/LoginPage.java b/samples/boot/redis/src/integration-test/java/sample/pages/LoginPage.java deleted file mode 100644 index e3e89f3..0000000 --- a/samples/boot/redis/src/integration-test/java/sample/pages/LoginPage.java +++ /dev/null @@ -1,69 +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.SearchContext; -import org.openqa.selenium.WebDriver; -import org.openqa.selenium.WebElement; -import org.openqa.selenium.support.FindBy; -import org.openqa.selenium.support.PageFactory; -import org.openqa.selenium.support.pagefactory.DefaultElementLocatorFactory; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Eddú Meléndez - * @author Rob Winch - */ -public class LoginPage extends BasePage { - - public LoginPage(WebDriver driver) { - super(driver); - } - - public void assertAt() { - assertThat(getDriver().getTitle()).isEqualTo("Login Page"); - } - - public Form form() { - return new Form(getDriver()); - } - - public class Form { - - @FindBy(name = "username") - private WebElement username; - - @FindBy(name = "password") - private WebElement password; - - @FindBy(name = "submit") - private WebElement button; - - public Form(SearchContext context) { - PageFactory.initElements(new DefaultElementLocatorFactory(context), this); - } - - public T login(Class page) { - this.username.sendKeys("user"); - this.password.sendKeys("password"); - this.button.click(); - return PageFactory.initElements(getDriver(), page); - } - } - -} diff --git a/samples/boot/redis/src/main/java/sample/Application.java b/samples/boot/redis/src/main/java/sample/Application.java deleted file mode 100644 index 02627e7..0000000 --- a/samples/boot/redis/src/main/java/sample/Application.java +++ /dev/null @@ -1,31 +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 org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -/** - * @author Rob Winch - */ -@SpringBootApplication -public class Application { - - public static void main(String[] args) { - SpringApplication.run(Application.class, args); - } -} diff --git a/samples/boot/redis/src/main/java/sample/config/HttpSessionConfig.java b/samples/boot/redis/src/main/java/sample/config/HttpSessionConfig.java deleted file mode 100644 index 2cba112..0000000 --- a/samples/boot/redis/src/main/java/sample/config/HttpSessionConfig.java +++ /dev/null @@ -1,25 +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.config; - -import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession; - -// tag::class[] -@EnableRedisHttpSession // <1> -public class HttpSessionConfig { -} -// end::class[] diff --git a/samples/boot/redis/src/main/java/sample/config/SecurityConfig.java b/samples/boot/redis/src/main/java/sample/config/SecurityConfig.java deleted file mode 100644 index 3ff7f23..0000000 --- a/samples/boot/redis/src/main/java/sample/config/SecurityConfig.java +++ /dev/null @@ -1,34 +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.config; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; - -/** - * @author Rob Winch - */ -@EnableWebSecurity -public class SecurityConfig extends WebSecurityConfigurerAdapter { - - @Autowired - public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { - auth.inMemoryAuthentication().withUser("user").password("password").roles("USER"); - } -} diff --git a/samples/boot/redis/src/main/java/sample/mvc/IndexController.java b/samples/boot/redis/src/main/java/sample/mvc/IndexController.java deleted file mode 100644 index 8c94fb3..0000000 --- a/samples/boot/redis/src/main/java/sample/mvc/IndexController.java +++ /dev/null @@ -1,34 +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.mvc; - -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.RequestMapping; - -/** - * Controller for sending the user to the login view. - * - * @author Rob Winch - * - */ -@Controller -public class IndexController { - @RequestMapping("/") - public String index() { - return "index"; - } -} diff --git a/samples/boot/redis/src/main/resources/application.properties b/samples/boot/redis/src/main/resources/application.properties deleted file mode 100644 index f0baad3..0000000 --- a/samples/boot/redis/src/main/resources/application.properties +++ /dev/null @@ -1,2 +0,0 @@ -spring.thymeleaf.cache=false -spring.template.cache=false diff --git a/samples/boot/redis/src/main/resources/static/resources/img/favicon.ico b/samples/boot/redis/src/main/resources/static/resources/img/favicon.ico deleted file mode 100644 index bfb9974..0000000 Binary files a/samples/boot/redis/src/main/resources/static/resources/img/favicon.ico and /dev/null differ diff --git a/samples/boot/redis/src/main/resources/static/resources/img/logo.png b/samples/boot/redis/src/main/resources/static/resources/img/logo.png deleted file mode 100644 index 3932308..0000000 Binary files a/samples/boot/redis/src/main/resources/static/resources/img/logo.png and /dev/null differ diff --git a/samples/boot/redis/src/main/resources/templates/index.html b/samples/boot/redis/src/main/resources/templates/index.html deleted file mode 100644 index 1e2703e..0000000 --- a/samples/boot/redis/src/main/resources/templates/index.html +++ /dev/null @@ -1,11 +0,0 @@ - - - Secured Content - - -
-

Secured Page

-

This page is secured using Spring Boot, Spring Session, and Spring Security.

-
- - diff --git a/samples/boot/redis/src/main/resources/templates/layout.html b/samples/boot/redis/src/main/resources/templates/layout.html deleted file mode 100644 index 7a66980..0000000 --- a/samples/boot/redis/src/main/resources/templates/layout.html +++ /dev/null @@ -1,122 +0,0 @@ - - - - Spring Session Sample - - - - - - - - - - - -
- - -
-
- Some Success message -
-
- Fake content -
-
- -
-
- - - - diff --git a/samples/boot/websocket/spring-session-sample-boot-websocket.gradle b/samples/boot/websocket/spring-session-sample-boot-websocket.gradle deleted file mode 100644 index acadcaa..0000000 --- a/samples/boot/websocket/spring-session-sample-boot-websocket.gradle +++ /dev/null @@ -1,30 +0,0 @@ -apply plugin: 'io.spring.convention.spring-sample-boot' - -dependencies { - compile(project(':spring-session-data-redis')) { - exclude module: 'jedis' - } - compile "org.springframework.boot:spring-boot-starter-data-jpa" - compile"org.springframework.boot:spring-boot-starter-thymeleaf" - compile"org.springframework.boot:spring-boot-starter-web" - compile"org.springframework.boot:spring-boot-starter-websocket" - compile"org.springframework:spring-websocket" - compile"nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect" - compile"io.lettuce:lettuce-core" - compile"org.webjars:bootstrap" - compile"org.webjars:html5shiv" - compile"org.webjars:knockout" - compile"org.webjars:sockjs-client" - compile"org.webjars:stomp-websocket" - compile"org.webjars:webjars-locator" - compile"com.h2database:h2" - compile"org.springframework.security:spring-security-web" - compile"org.springframework.security:spring-security-config" - compile"org.springframework.security:spring-security-messaging" - compile"org.springframework.security:spring-security-data" - - - testCompile "org.springframework.boot:spring-boot-starter-test" - testCompile "org.springframework.security:spring-security-test" - -} diff --git a/samples/boot/websocket/src/main/java/sample/Application.java b/samples/boot/websocket/src/main/java/sample/Application.java deleted file mode 100644 index 973e145..0000000 --- a/samples/boot/websocket/src/main/java/sample/Application.java +++ /dev/null @@ -1,35 +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 org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; - -/** - * @author Rob Winch - */ -@Configuration -@ComponentScan -@EnableAutoConfiguration -public class Application { - - public static void main(String[] args) { - SpringApplication.run(Application.class, args); - } -} diff --git a/samples/boot/websocket/src/main/java/sample/config/DataSourceConfig.java b/samples/boot/websocket/src/main/java/sample/config/DataSourceConfig.java deleted file mode 100644 index b8e5a55..0000000 --- a/samples/boot/websocket/src/main/java/sample/config/DataSourceConfig.java +++ /dev/null @@ -1,40 +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.config; - -import javax.sql.DataSource; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; -import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; -import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; - -@Configuration -public class DataSourceConfig { - - @Bean - public DataSource dataSource() { - EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder(); - return builder.setType(EmbeddedDatabaseType.H2).build(); - } - - @Bean - public LettuceConnectionFactory connectionFactory() { - return new LettuceConnectionFactory(); - } -} diff --git a/samples/boot/websocket/src/main/java/sample/config/WebSecurityConfig.java b/samples/boot/websocket/src/main/java/sample/config/WebSecurityConfig.java deleted file mode 100644 index 6579ca4..0000000 --- a/samples/boot/websocket/src/main/java/sample/config/WebSecurityConfig.java +++ /dev/null @@ -1,76 +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.config; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; -import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.builders.WebSecurity; -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; -import org.springframework.security.core.userdetails.UserDetailsService; -import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; -import org.springframework.security.data.repository.query.SecurityEvaluationContextExtension; -import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession; - -@Configuration -@EnableWebSecurity -@EnableGlobalMethodSecurity(prePostEnabled = true) -// tag::enable-redis-httpsession[] -@EnableRedisHttpSession // (maxInactiveIntervalInSeconds = 60) -public class WebSecurityConfig extends WebSecurityConfigurerAdapter { - // end::enable-redis-httpsession[] - - // @formatter:off - @Override - protected void configure(HttpSecurity http) throws Exception { - http - .authorizeRequests() - .anyRequest().authenticated() - .and() - .formLogin() - .and() - .logout() - .permitAll(); - } - // @formatter:on - - // @formatter:off - @Override - public void configure(WebSecurity web) throws Exception { - web - .ignoring().antMatchers("/h2-console/**"); - } - // @formatter:on - - // @formatter:off - @Autowired - public void configureGlobal(AuthenticationManagerBuilder auth, UserDetailsService userDetailsService) throws Exception { - auth - .userDetailsService(userDetailsService) - .passwordEncoder(new BCryptPasswordEncoder()); - } - // @formatter:on - - @Bean - public SecurityEvaluationContextExtension securityEvaluationContextExtension() { - return new SecurityEvaluationContextExtension(); - } -} diff --git a/samples/boot/websocket/src/main/java/sample/config/WebSocketConfig.java b/samples/boot/websocket/src/main/java/sample/config/WebSocketConfig.java deleted file mode 100644 index 8a28a55..0000000 --- a/samples/boot/websocket/src/main/java/sample/config/WebSocketConfig.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.config; - -import org.springframework.context.annotation.Configuration; -import org.springframework.messaging.simp.config.MessageBrokerRegistry; -import org.springframework.scheduling.annotation.EnableScheduling; -import org.springframework.session.ExpiringSession; -import org.springframework.session.web.socket.config.annotation.AbstractSessionWebSocketMessageBrokerConfigurer; -import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker; -import org.springframework.web.socket.config.annotation.StompEndpointRegistry; - -// tag::class[] -@Configuration -@EnableScheduling -@EnableWebSocketMessageBroker -public class WebSocketConfig - extends AbstractSessionWebSocketMessageBrokerConfigurer { // <1> - - protected void configureStompEndpoints(StompEndpointRegistry registry) { // <2> - registry.addEndpoint("/messages").withSockJS(); - } - - public void configureMessageBroker(MessageBrokerRegistry registry) { - registry.enableSimpleBroker("/queue/", "/topic/"); - registry.setApplicationDestinationPrefixes("/app"); - } -} -// end::class[] diff --git a/samples/boot/websocket/src/main/java/sample/config/WebSocketHandlersConfig.java b/samples/boot/websocket/src/main/java/sample/config/WebSocketHandlersConfig.java deleted file mode 100644 index 356216a..0000000 --- a/samples/boot/websocket/src/main/java/sample/config/WebSocketHandlersConfig.java +++ /dev/null @@ -1,50 +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.config; - -import sample.data.ActiveWebSocketUserRepository; -import sample.websocket.WebSocketConnectHandler; -import sample.websocket.WebSocketDisconnectHandler; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.messaging.simp.SimpMessageSendingOperations; -import org.springframework.session.ExpiringSession; - -/** - * These handlers are separated from WebSocketConfig because they are specific to this - * application and do not demonstrate a typical Spring Session setup. - * - * @author Rob Winch - */ -@Configuration -public class WebSocketHandlersConfig { - - @Bean - public WebSocketConnectHandler webSocketConnectHandler( - SimpMessageSendingOperations messagingTemplate, - ActiveWebSocketUserRepository repository) { - return new WebSocketConnectHandler(messagingTemplate, repository); - } - - @Bean - public WebSocketDisconnectHandler webSocketDisconnectHandler( - SimpMessageSendingOperations messagingTemplate, - ActiveWebSocketUserRepository repository) { - return new WebSocketDisconnectHandler(messagingTemplate, repository); - } -} diff --git a/samples/boot/websocket/src/main/java/sample/config/WebSocketSecurityConfig.java b/samples/boot/websocket/src/main/java/sample/config/WebSocketSecurityConfig.java deleted file mode 100644 index ed411aa..0000000 --- a/samples/boot/websocket/src/main/java/sample/config/WebSocketSecurityConfig.java +++ /dev/null @@ -1,39 +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.config; - -import org.springframework.context.annotation.Configuration; -import org.springframework.security.config.annotation.web.messaging.MessageSecurityMetadataSourceRegistry; -import org.springframework.security.config.annotation.web.socket.AbstractSecurityWebSocketMessageBrokerConfigurer; - -/** - * @author Rob Winch - */ -@Configuration -public class WebSocketSecurityConfig - extends AbstractSecurityWebSocketMessageBrokerConfigurer { - - // @formatter:off - @Override - protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) { - messages - .simpMessageDestMatchers("/queue/**", "/topic/**").denyAll() - .simpSubscribeDestMatchers("/queue/**/*-user*", "/topic/**/*-user*").denyAll() - .anyMessage().authenticated(); - } - // @formatter:on -} diff --git a/samples/boot/websocket/src/main/java/sample/data/ActiveWebSocketUser.java b/samples/boot/websocket/src/main/java/sample/data/ActiveWebSocketUser.java deleted file mode 100644 index af45676..0000000 --- a/samples/boot/websocket/src/main/java/sample/data/ActiveWebSocketUser.java +++ /dev/null @@ -1,59 +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.data; - -import java.util.Calendar; - -import javax.persistence.Entity; -import javax.persistence.Id; - -@Entity -public class ActiveWebSocketUser { - @Id - private String id; - - private String username; - - private Calendar connectionTime; - - public ActiveWebSocketUser() { - } - - public ActiveWebSocketUser(String id, String username, Calendar connectionTime) { - super(); - this.id = id; - this.username = username; - this.connectionTime = connectionTime; - } - - public String getUsername() { - return this.username; - } - - public void setUsername(String username) { - this.username = username; - } - - public Calendar getConnectionTime() { - return this.connectionTime; - } - - public void setConnectionTime(Calendar connectionTime) { - this.connectionTime = connectionTime; - } - -} diff --git a/samples/boot/websocket/src/main/java/sample/data/ActiveWebSocketUserRepository.java b/samples/boot/websocket/src/main/java/sample/data/ActiveWebSocketUserRepository.java deleted file mode 100644 index 49d8c14..0000000 --- a/samples/boot/websocket/src/main/java/sample/data/ActiveWebSocketUserRepository.java +++ /dev/null @@ -1,29 +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.data; - -import java.util.List; - -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.CrudRepository; - -public interface ActiveWebSocketUserRepository - extends CrudRepository { - - @Query("select DISTINCT(u.username) from ActiveWebSocketUser u where u.username != ?#{principal?.username}") - List findAllActiveUsers(); -} diff --git a/samples/boot/websocket/src/main/java/sample/data/InstantMessage.java b/samples/boot/websocket/src/main/java/sample/data/InstantMessage.java deleted file mode 100644 index e916746..0000000 --- a/samples/boot/websocket/src/main/java/sample/data/InstantMessage.java +++ /dev/null @@ -1,62 +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.data; - -import java.util.Calendar; - -public class InstantMessage { - private String to; - - private String from; - - private String message; - - private Calendar created = Calendar.getInstance(); - - public String getTo() { - return this.to; - } - - public void setTo(String to) { - this.to = to; - } - - public String getFrom() { - return this.from; - } - - public void setFrom(String from) { - this.from = from; - } - - public String getMessage() { - return this.message; - } - - public void setMessage(String message) { - this.message = message; - } - - public Calendar getCreated() { - return this.created; - } - - public void setCreated(Calendar created) { - this.created = created; - } - -} diff --git a/samples/boot/websocket/src/main/java/sample/data/User.java b/samples/boot/websocket/src/main/java/sample/data/User.java deleted file mode 100644 index ffec2fa..0000000 --- a/samples/boot/websocket/src/main/java/sample/data/User.java +++ /dev/null @@ -1,115 +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.data; - -import java.io.Serializable; - -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; - -import org.hibernate.validator.constraints.Email; -import org.hibernate.validator.constraints.NotEmpty; - -import org.springframework.security.crypto.password.PasswordEncoder; - -/** - * Represents a user in our system. - * - *

- * In a real system use {@link PasswordEncoder} to ensure the password is secured - * properly. This demonstration does not address this due to time restrictions. - *

- * - * @author Rob Winch - */ -@Entity -public class User implements Serializable { - - @Id - @GeneratedValue(strategy = GenerationType.AUTO) - private Long id; - - @NotEmpty(message = "First name is required.") - private String firstName; - - @NotEmpty(message = "Last name is required.") - private String lastName; - - @Email(message = "Please provide a valid email address.") - @NotEmpty(message = "Email is required.") - @Column(unique = true, nullable = false) - private String email; - - @NotEmpty(message = "Password is required.") - private String password; - - public User() { - } - - public User(User user) { - this.id = user.id; - this.firstName = user.firstName; - this.lastName = user.lastName; - this.email = user.email; - this.password = user.password; - } - - public String getPassword() { - return this.password; - } - - public void setPassword(String password) { - this.password = password; - } - - public Long getId() { - return this.id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getFirstName() { - return this.firstName; - } - - public void setFirstName(String firstName) { - this.firstName = firstName; - } - - public String getLastName() { - return this.lastName; - } - - public void setLastName(String lastName) { - this.lastName = lastName; - } - - public String getEmail() { - return this.email; - } - - public void setEmail(String email) { - this.email = email; - } - - private static final long serialVersionUID = 2738859149330833739L; -} diff --git a/samples/boot/websocket/src/main/java/sample/data/UserRepository.java b/samples/boot/websocket/src/main/java/sample/data/UserRepository.java deleted file mode 100644 index 6790616..0000000 --- a/samples/boot/websocket/src/main/java/sample/data/UserRepository.java +++ /dev/null @@ -1,30 +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.data; - -import org.springframework.data.repository.CrudRepository; - -/** - * Allows managing {@link User} instances. - * - * @author Rob Winch - * - */ -public interface UserRepository extends CrudRepository { - - User findByEmail(String email); -} diff --git a/samples/boot/websocket/src/main/java/sample/mvc/CsrfController.java b/samples/boot/websocket/src/main/java/sample/mvc/CsrfController.java deleted file mode 100644 index 87feddc..0000000 --- a/samples/boot/websocket/src/main/java/sample/mvc/CsrfController.java +++ /dev/null @@ -1,30 +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.mvc; - -import org.springframework.security.web.csrf.CsrfToken; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -public class CsrfController { - - @RequestMapping("/csrf") - public CsrfToken csrf(CsrfToken token) { - return token; - } -} diff --git a/samples/boot/websocket/src/main/java/sample/mvc/MessageController.java b/samples/boot/websocket/src/main/java/sample/mvc/MessageController.java deleted file mode 100644 index 91e7668..0000000 --- a/samples/boot/websocket/src/main/java/sample/mvc/MessageController.java +++ /dev/null @@ -1,69 +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.mvc; - -import java.util.List; - -import sample.data.ActiveWebSocketUserRepository; -import sample.data.InstantMessage; -import sample.data.User; -import sample.security.CurrentUser; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.messaging.Message; -import org.springframework.messaging.handler.annotation.MessageMapping; -import org.springframework.messaging.simp.SimpMessageSendingOperations; -import org.springframework.messaging.simp.annotation.SubscribeMapping; -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.RequestMapping; - -/** - * Controller for managing {@link Message} instances. - * - * @author Rob Winch - * - */ -@Controller -@RequestMapping("/") -public class MessageController { - private SimpMessageSendingOperations messagingTemplate; - private ActiveWebSocketUserRepository activeUserRepository; - - @Autowired - public MessageController(ActiveWebSocketUserRepository activeUserRepository, - SimpMessageSendingOperations messagingTemplate) { - this.activeUserRepository = activeUserRepository; - this.messagingTemplate = messagingTemplate; - } - - @RequestMapping("/") - public String im() { - return "index"; - } - - @MessageMapping("/im") - public void im(InstantMessage im, @CurrentUser User currentUser) { - im.setFrom(currentUser.getEmail()); - this.messagingTemplate.convertAndSendToUser(im.getTo(), "/queue/messages", im); - this.messagingTemplate.convertAndSendToUser(im.getFrom(), "/queue/messages", im); - } - - @SubscribeMapping("/users") - public List subscribeMessages() throws Exception { - return this.activeUserRepository.findAllActiveUsers(); - } -} diff --git a/samples/boot/websocket/src/main/java/sample/security/CurrentUser.java b/samples/boot/websocket/src/main/java/sample/security/CurrentUser.java deleted file mode 100644 index 345bd56..0000000 --- a/samples/boot/websocket/src/main/java/sample/security/CurrentUser.java +++ /dev/null @@ -1,49 +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.security; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import org.springframework.security.core.Authentication; -import org.springframework.security.core.annotation.AuthenticationPrincipal; -import org.springframework.security.core.context.SecurityContextHolder; - -/** - * Annotate Spring MVC method arguments with this annotation to indicate you wish to - * specify the argument with the value of the current - * {@link Authentication#getPrincipal()} found on the {@link SecurityContextHolder}. - * - *

- * Creating your own annotation that uses {@link AuthenticationPrincipal} as a meta - * annotation creates a layer of indirection between your code and Spring Security's. For - * simplicity, you could instead use the {@link AuthenticationPrincipal} directly. - *

- * - * @author Rob Winch - * - */ -@Target(ElementType.PARAMETER) -@Retention(RetentionPolicy.RUNTIME) -@Documented -@AuthenticationPrincipal -public @interface CurrentUser { - -} diff --git a/samples/boot/websocket/src/main/java/sample/security/UserRepositoryUserDetailsService.java b/samples/boot/websocket/src/main/java/sample/security/UserRepositoryUserDetailsService.java deleted file mode 100644 index a97a2e2..0000000 --- a/samples/boot/websocket/src/main/java/sample/security/UserRepositoryUserDetailsService.java +++ /dev/null @@ -1,93 +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.security; - -import java.util.Collection; - -import sample.data.User; -import sample.data.UserRepository; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.AuthorityUtils; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.core.userdetails.UserDetailsService; -import org.springframework.security.core.userdetails.UsernameNotFoundException; -import org.springframework.stereotype.Service; - -/** - * @author Rob Winch - * - */ -@Service -public class UserRepositoryUserDetailsService implements UserDetailsService { - private final UserRepository userRepository; - - @Autowired - public UserRepositoryUserDetailsService(UserRepository userRepository) { - this.userRepository = userRepository; - } - - /* - * (non-Javadoc) - * - * @see - * org.springframework.security.core.userdetails.UserDetailsService#loadUserByUsername - * (java.lang.String) - */ - public UserDetails loadUserByUsername(String username) - throws UsernameNotFoundException { - User user = this.userRepository.findByEmail(username); - if (user == null) { - throw new UsernameNotFoundException("Could not find user " + username); - } - return new CustomUserDetails(user); - } - - private final static class CustomUserDetails extends User implements UserDetails { - - private CustomUserDetails(User user) { - super(user); - } - - public Collection getAuthorities() { - return AuthorityUtils.createAuthorityList("ROLE_USER"); - } - - public String getUsername() { - return getEmail(); - } - - public boolean isAccountNonExpired() { - return true; - } - - public boolean isAccountNonLocked() { - return true; - } - - public boolean isCredentialsNonExpired() { - return true; - } - - public boolean isEnabled() { - return true; - } - - private static final long serialVersionUID = 5639683223516504866L; - } -} diff --git a/samples/boot/websocket/src/main/java/sample/websocket/WebSocketConnectHandler.java b/samples/boot/websocket/src/main/java/sample/websocket/WebSocketConnectHandler.java deleted file mode 100644 index 060381a..0000000 --- a/samples/boot/websocket/src/main/java/sample/websocket/WebSocketConnectHandler.java +++ /dev/null @@ -1,56 +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.websocket; - -import java.security.Principal; -import java.util.Arrays; -import java.util.Calendar; - -import sample.data.ActiveWebSocketUser; -import sample.data.ActiveWebSocketUserRepository; - -import org.springframework.context.ApplicationListener; -import org.springframework.messaging.MessageHeaders; -import org.springframework.messaging.simp.SimpMessageHeaderAccessor; -import org.springframework.messaging.simp.SimpMessageSendingOperations; -import org.springframework.web.socket.messaging.SessionConnectEvent; - -public class WebSocketConnectHandler - implements ApplicationListener { - private ActiveWebSocketUserRepository repository; - private SimpMessageSendingOperations messagingTemplate; - - public WebSocketConnectHandler(SimpMessageSendingOperations messagingTemplate, - ActiveWebSocketUserRepository repository) { - super(); - this.messagingTemplate = messagingTemplate; - this.repository = repository; - } - - public void onApplicationEvent(SessionConnectEvent event) { - MessageHeaders headers = event.getMessage().getHeaders(); - Principal user = SimpMessageHeaderAccessor.getUser(headers); - if (user == null) { - return; - } - String id = SimpMessageHeaderAccessor.getSessionId(headers); - this.repository.save( - new ActiveWebSocketUser(id, user.getName(), Calendar.getInstance())); - this.messagingTemplate.convertAndSend("/topic/friends/signin", - Arrays.asList(user.getName())); - } -} diff --git a/samples/boot/websocket/src/main/java/sample/websocket/WebSocketDisconnectHandler.java b/samples/boot/websocket/src/main/java/sample/websocket/WebSocketDisconnectHandler.java deleted file mode 100644 index 6d7d3be..0000000 --- a/samples/boot/websocket/src/main/java/sample/websocket/WebSocketDisconnectHandler.java +++ /dev/null @@ -1,56 +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.websocket; - -import java.util.Arrays; -import java.util.Optional; - -import sample.data.ActiveWebSocketUser; -import sample.data.ActiveWebSocketUserRepository; - -import org.springframework.context.ApplicationListener; -import org.springframework.messaging.simp.SimpMessageSendingOperations; -import org.springframework.web.socket.messaging.SessionDisconnectEvent; - -public class WebSocketDisconnectHandler - implements ApplicationListener { - private ActiveWebSocketUserRepository repository; - private SimpMessageSendingOperations messagingTemplate; - - public WebSocketDisconnectHandler(SimpMessageSendingOperations messagingTemplate, - ActiveWebSocketUserRepository repository) { - super(); - this.messagingTemplate = messagingTemplate; - this.repository = repository; - } - - public void onApplicationEvent(SessionDisconnectEvent event) { - String id = event.getSessionId(); - if (id == null) { - return; - } - Optional user = this.repository.findOne(id); - if (!user.isPresent()) { - return; - } - - this.repository.delete(id); - this.messagingTemplate.convertAndSend("/topic/friends/signout", - Arrays.asList(user.get().getUsername())); - - } -} diff --git a/samples/boot/websocket/src/main/resources/application.properties b/samples/boot/websocket/src/main/resources/application.properties deleted file mode 100644 index 16b8068..0000000 --- a/samples/boot/websocket/src/main/resources/application.properties +++ /dev/null @@ -1,3 +0,0 @@ -spring.thymeleaf.cache=false -spring.template.cache=false -spring.h2.console.enabled=true diff --git a/samples/boot/websocket/src/main/resources/data.sql b/samples/boot/websocket/src/main/resources/data.sql deleted file mode 100644 index 56b0748..0000000 --- a/samples/boot/websocket/src/main/resources/data.sql +++ /dev/null @@ -1,5 +0,0 @@ -insert into user(id,email,password,first_name,last_name) values (0,'rob','password','Rob','Winch'); -insert into user(id,email,password,first_name,last_name) values (1,'luke','password','Luke','Taylor'); -insert into user(id,email,password,first_name,last_name) values (2,'eve','password','Luke','Taylor'); - -update user set password = '$2a$10$FBAKClV1zBIOOC9XMXf3AO8RoGXYVYsfvUdoLxGkd/BnXEn4tqT3u'; diff --git a/samples/boot/websocket/src/main/resources/static/resources/img/favicon.ico b/samples/boot/websocket/src/main/resources/static/resources/img/favicon.ico deleted file mode 100644 index bfb9974..0000000 Binary files a/samples/boot/websocket/src/main/resources/static/resources/img/favicon.ico and /dev/null differ diff --git a/samples/boot/websocket/src/main/resources/static/resources/img/logo.png b/samples/boot/websocket/src/main/resources/static/resources/img/logo.png deleted file mode 100644 index 3932308..0000000 Binary files a/samples/boot/websocket/src/main/resources/static/resources/img/logo.png and /dev/null differ diff --git a/samples/boot/websocket/src/main/resources/static/resources/js/message.js b/samples/boot/websocket/src/main/resources/static/resources/js/message.js deleted file mode 100644 index 0febaf7..0000000 --- a/samples/boot/websocket/src/main/resources/static/resources/js/message.js +++ /dev/null @@ -1,152 +0,0 @@ - -function ApplicationModel(stompClient) { - var self = this; - - self.friends = ko.observableArray(); - self.username = ko.observable(); - self.conversation = ko.observable(new ImConversationModel(stompClient,this.username)); - self.notifications = ko.observableArray(); - self.csrfToken = ko.computed(function() { - return JSON.parse($.ajax({ - type: 'GET', - url: 'csrf', - dataType: 'json', - success: function() { }, - data: {}, - async: false - }).responseText); - }, this); - - self.connect = function() { - var headers = {}; - var csrf = self.csrfToken(); - headers[csrf.headerName] = csrf.token; - stompClient.connect(headers, function(frame) { - - console.log('Connected ' + frame); - self.username(frame.headers['user-name']); - -// self.friendSignin({"username": "luke"}); - - stompClient.subscribe("/user/queue/errors", function(message) { - self.pushNotification("Error " + message.body); - }); - stompClient.subscribe("/app/users", function(message) { - var friends = JSON.parse(message.body); - - for(var i=0;i 5) { - self.notifications.shift(); - } - } - - self.logout = function() { - stompClient.disconnect(); - window.location.href = "../logout.html"; - } - - self.friendSignin = function(friend) { - self.friends.push(friend); - } - - self.friendSignout = function(friend) { - var r = self.friends.remove( - function(item) { - item.username == friend.username - } - ); - self.friends(r); - } -} - -function ImFriend(data) { - var self = this; - - self.username = data.username; -} - -function ImConversationModel(stompClient,from) { - var self = this; - self.stompClient = stompClient; - self.from = from; - self.to = ko.observable(new ImFriend('null')); - self.draft = ko.observable('') - - self.messages = ko.observableArray(); - - self.receiveMessage = function(message) { - var elem = $('#chat'); - var isFromSelf = self.from() == message.from; - var isFromTo = self.to().username == message.from; - if(!(isFromTo || isFromSelf)) { - self.chat(new ImFriend({"username":message.from})) - } - - var atBottom = (elem[0].scrollHeight - elem.scrollTop() == elem.outerHeight()); - - self.messages.push(new ImModel(message)); - - if (atBottom) - elem.scrollTop(elem[0].scrollHeight); - }; - - self.chat = function(to) { - self.to(to); - self.draft(''); - self.messages.removeAll() - $('#trade-dialog').modal(); - } - - self.send = function() { - var data = { - "created" : new Date(), - "from" : self.from(), - "to" : self.to().username, - "message" : self.draft() - }; - var destination = "/app/im"; // /queue/messages-user1 - stompClient.send(destination, {}, JSON.stringify(data)); - self.draft(''); - } -}; - -function ImModel(data) { - var self = this; - - self.created = new Date(data.created); - self.to = data.to; - self.message = data.message; - self.from = data.from; - self.messageFormatted = ko.computed(function() { - return self.created.getHours() + ":" + self.created.getMinutes() + ":" + self.created.getSeconds() + " - " + self.from + " - " + self.message; - }) -}; - diff --git a/samples/boot/websocket/src/main/resources/templates/index.html b/samples/boot/websocket/src/main/resources/templates/index.html deleted file mode 100644 index 328a3b4..0000000 --- a/samples/boot/websocket/src/main/resources/templates/index.html +++ /dev/null @@ -1,74 +0,0 @@ - - - View All - - -
-
-
-

Chat Application

-
-
- - - - - - - - - - - - - -
User
- -
- - -
-
Notifications
-
    -
  • -
-
-
-
- - - - - - - - - - - - -
- - diff --git a/samples/boot/websocket/src/main/resources/templates/layout.html b/samples/boot/websocket/src/main/resources/templates/layout.html deleted file mode 100644 index 5f47ed2..0000000 --- a/samples/boot/websocket/src/main/resources/templates/layout.html +++ /dev/null @@ -1,124 +0,0 @@ - - - - SecureMail - - - - - - - - - - - -
- - -
-
- Some Success message -
-
- Fake content -
-
- -
-
- - - - diff --git a/samples/boot/websocket/src/test/java/sample/ApplicationTests.java b/samples/boot/websocket/src/test/java/sample/ApplicationTests.java deleted file mode 100644 index c71bd48..0000000 --- a/samples/boot/websocket/src/test/java/sample/ApplicationTests.java +++ /dev/null @@ -1,70 +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.util.ArrayList; -import java.util.List; -import java.util.concurrent.ExecutionException; - -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.junit.runner.RunWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringRunner; -import org.springframework.util.concurrent.ListenableFuture; -import org.springframework.web.socket.TextMessage; -import org.springframework.web.socket.WebSocketHandler; -import org.springframework.web.socket.WebSocketSession; -import org.springframework.web.socket.client.standard.StandardWebSocketClient; -import org.springframework.web.socket.sockjs.client.RestTemplateXhrTransport; -import org.springframework.web.socket.sockjs.client.SockJsClient; -import org.springframework.web.socket.sockjs.client.Transport; -import org.springframework.web.socket.sockjs.client.WebSocketTransport; - -/** - * @author Rob Winch - */ -@RunWith(SpringRunner.class) -@SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) -public class ApplicationTests { - @Rule - public final ExpectedException thrown = ExpectedException.none(); - - @Value("${local.server.port}") - String port; - - @Autowired - WebSocketHandler webSocketHandler; - - @Test - public void run() throws Exception { - List transports = new ArrayList(2); - transports.add(new WebSocketTransport(new StandardWebSocketClient())); - transports.add(new RestTemplateXhrTransport()); - - SockJsClient sockJsClient = new SockJsClient(transports); - ListenableFuture wsSession = sockJsClient.doHandshake( - this.webSocketHandler, "ws://localhost:" + this.port + "/sockjs"); - - this.thrown.expect(ExecutionException.class); - wsSession.get().sendMessage(new TextMessage("a")); - } -} diff --git a/samples/javaconfig/custom-cookie/spring-session-sample-javaconfig-custom-cookie.gradle b/samples/javaconfig/custom-cookie/spring-session-sample-javaconfig-custom-cookie.gradle deleted file mode 100644 index bc4d612..0000000 --- a/samples/javaconfig/custom-cookie/spring-session-sample-javaconfig-custom-cookie.gradle +++ /dev/null @@ -1,20 +0,0 @@ -apply plugin: 'io.spring.convention.spring-sample-war' - -dependencies { - compile(project(':spring-session-data-redis')) { - exclude module: 'jedis' - } - compile "org.springframework:spring-web" - compile "io.lettuce:lettuce-core" - compile "org.webjars:bootstrap" - compile "org.webjars:webjars-taglib" - compile jstlDependencies - compile slf4jDependencies - - providedCompile "javax.servlet:javax.servlet-api" - - testCompile "junit:junit" - testCompile "org.assertj:assertj-core" - - integrationTestCompile seleniumDependencies -} diff --git a/samples/javaconfig/custom-cookie/src/integration-test/java/sample/AttributeTests.java b/samples/javaconfig/custom-cookie/src/integration-test/java/sample/AttributeTests.java deleted file mode 100644 index 97b8342..0000000 --- a/samples/javaconfig/custom-cookie/src/integration-test/java/sample/AttributeTests.java +++ /dev/null @@ -1,78 +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.util.List; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.openqa.selenium.WebDriver; -import org.openqa.selenium.htmlunit.HtmlUnitDriver; -import sample.pages.HomePage; -import sample.pages.HomePage.Attribute; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Eddú Meléndez - * @author Rob Winch - */ -public class AttributeTests { - - private WebDriver driver; - - @Before - public void setup() { - this.driver = new HtmlUnitDriver(); - } - - @After - public void tearDown() { - this.driver.quit(); - } - - @Test - public void home() { - HomePage home = HomePage.go(this.driver); - home.assertAt(); - } - - @Test - public void noAttributes() { - HomePage home = HomePage.go(this.driver); - assertThat(home.attributes()).isEmpty(); - } - - @Test - public void createAttribute() { - HomePage home = HomePage.go(this.driver); - // @formatter:off - home = home.form() - .attributeName("a") - .attributeValue("b") - .submit(HomePage.class); - // @formatter:on - - List attributes = home.attributes(); - assertThat(attributes).hasSize(1); - Attribute row = attributes.get(0); - assertThat(row.getAttributeName()).isEqualTo("a"); - assertThat(row.getAttributeValue()).isEqualTo("b"); - } - -} diff --git a/samples/javaconfig/custom-cookie/src/integration-test/java/sample/pages/HomePage.java b/samples/javaconfig/custom-cookie/src/integration-test/java/sample/pages/HomePage.java deleted file mode 100644 index e9e0134..0000000 --- a/samples/javaconfig/custom-cookie/src/integration-test/java/sample/pages/HomePage.java +++ /dev/null @@ -1,135 +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 java.util.ArrayList; -import java.util.List; - -import org.openqa.selenium.SearchContext; -import org.openqa.selenium.WebDriver; -import org.openqa.selenium.WebElement; -import org.openqa.selenium.support.FindBy; -import org.openqa.selenium.support.PageFactory; -import org.openqa.selenium.support.pagefactory.DefaultElementLocatorFactory; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Eddú Meléndez - * @author Rob Winch - */ -public class HomePage { - - private WebDriver driver; - - @FindBy(css = "form") - WebElement form; - - @FindBy(css = "table tbody tr") - List trs; - - List attributes; - - public HomePage(WebDriver driver) { - this.driver = driver; - this.attributes = new ArrayList(); - } - - private static void get(WebDriver driver, String get) { - String baseUrl = "http://localhost:" + System.getProperty("app.port", "8080"); - driver.get(baseUrl + get); - } - - public static HomePage go(WebDriver driver) { - get(driver, "/"); - return PageFactory.initElements(driver, HomePage.class); - } - - public void assertAt() { - assertThat(this.driver.getTitle()).isEqualTo("Session Attributes"); - } - - public List attributes() { - List rows = new ArrayList(); - for (WebElement tr : this.trs) { - rows.add(new Attribute(tr)); - } - this.attributes.addAll(rows); - return this.attributes; - } - - public Form form() { - return new Form(this.form); - } - - public class Form { - @FindBy(name = "attributeName") - WebElement attributeName; - - @FindBy(name = "attributeValue") - WebElement attributeValue; - - @FindBy(css = "input[type=\"submit\"]") - WebElement submit; - - public Form(SearchContext context) { - PageFactory.initElements(new DefaultElementLocatorFactory(context), this); - } - - public Form attributeName(String text) { - this.attributeName.sendKeys(text); - return this; - } - - public Form attributeValue(String text) { - this.attributeValue.sendKeys(text); - return this; - } - - public T submit(Class page) { - this.submit.click(); - return PageFactory.initElements(HomePage.this.driver, page); - } - } - - public static class Attribute { - @FindBy(xpath = ".//td[1]") - WebElement attributeName; - - @FindBy(xpath = ".//td[2]") - WebElement attributeValue; - - public Attribute(SearchContext context) { - PageFactory.initElements(new DefaultElementLocatorFactory(context), this); - } - - /** - * @return the attributeName - */ - public String getAttributeName() { - return this.attributeName.getText(); - } - - /** - * @return the attributeValue - */ - public String getAttributeValue() { - return this.attributeValue.getText(); - } - } - -} diff --git a/samples/javaconfig/custom-cookie/src/main/java/sample/Config.java b/samples/javaconfig/custom-cookie/src/main/java/sample/Config.java deleted file mode 100644 index 92bff82..0000000 --- a/samples/javaconfig/custom-cookie/src/main/java/sample/Config.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 org.springframework.context.annotation.Bean; -import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; -import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession; -import org.springframework.session.web.http.CookieSerializer; -import org.springframework.session.web.http.DefaultCookieSerializer; - -@EnableRedisHttpSession -public class Config { - - @Bean - public LettuceConnectionFactory connectionFactory() { - return new LettuceConnectionFactory(); - } - - // tag::cookie-serializer[] - @Bean - public CookieSerializer cookieSerializer() { - DefaultCookieSerializer serializer = new DefaultCookieSerializer(); - serializer.setCookieName("JSESSIONID"); // <1> - serializer.setCookiePath("/"); // <2> - serializer.setDomainNamePattern("^.+?\\.(\\w+\\.[a-z]+)$"); // <3> - return serializer; - } - // end::cookie-serializer[] -} diff --git a/samples/javaconfig/custom-cookie/src/main/java/sample/Initializer.java b/samples/javaconfig/custom-cookie/src/main/java/sample/Initializer.java deleted file mode 100644 index b7472d1..0000000 --- a/samples/javaconfig/custom-cookie/src/main/java/sample/Initializer.java +++ /dev/null @@ -1,28 +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 org.springframework.session.web.context.AbstractHttpSessionApplicationInitializer; - -// tag::class[] -public class Initializer extends AbstractHttpSessionApplicationInitializer { // <1> - - public Initializer() { - super(Config.class); // <2> - } -} -// end::class[] diff --git a/samples/javaconfig/custom-cookie/src/main/java/sample/SessionServlet.java b/samples/javaconfig/custom-cookie/src/main/java/sample/SessionServlet.java deleted file mode 100644 index 5e0a06f..0000000 --- a/samples/javaconfig/custom-cookie/src/main/java/sample/SessionServlet.java +++ /dev/null @@ -1,42 +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; - -// tag::class[] -@WebServlet("/session") -public class SessionServlet extends HttpServlet { - - @Override - protected void doPost(HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException { - String attributeName = req.getParameter("attributeName"); - String attributeValue = req.getParameter("attributeValue"); - req.getSession().setAttribute(attributeName, attributeValue); - resp.sendRedirect(req.getContextPath() + "/"); - } - - private static final long serialVersionUID = 2878267318695777395L; -} -// tag::end[] diff --git a/samples/javaconfig/custom-cookie/src/main/webapp/META-INF/MANIFEST.MF b/samples/javaconfig/custom-cookie/src/main/webapp/META-INF/MANIFEST.MF deleted file mode 100644 index e69de29..0000000 diff --git a/samples/javaconfig/custom-cookie/src/main/webapp/index.jsp b/samples/javaconfig/custom-cookie/src/main/webapp/index.jsp deleted file mode 100644 index 8a273e5..0000000 --- a/samples/javaconfig/custom-cookie/src/main/webapp/index.jsp +++ /dev/null @@ -1,50 +0,0 @@ -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> -<%@ taglib prefix="wj" uri="http://www.webjars.org/tags" %> - - - - Session Attributes - - "> - - - -
-

Description

-

This application demonstrates how to use a Redis instance to back your session. Notice that there is no JSESSIONID cookie. We are also able to customize the way of identifying what the requested session id is.

- -

Try it

- -
- - - - - -
- -
- - - - - - - - - - - - - - - - -
Attribute NameAttribute Value
-
- - diff --git a/samples/javaconfig/hazelcast/spring-session-sample-javaconfig-hazelcast.gradle b/samples/javaconfig/hazelcast/spring-session-sample-javaconfig-hazelcast.gradle deleted file mode 100644 index 05d8015..0000000 --- a/samples/javaconfig/hazelcast/spring-session-sample-javaconfig-hazelcast.gradle +++ /dev/null @@ -1,21 +0,0 @@ -apply plugin: 'io.spring.convention.spring-sample-war' - -dependencies { - compile project(':spring-session') - compile "org.springframework:spring-web" - compile "org.springframework.security:spring-security-config" - compile "org.springframework.security:spring-security-web" - compile "org.webjars:bootstrap" - compile "org.webjars:webjars-taglib" - compile "com.hazelcast:hazelcast-client" - compile jstlDependencies - compile slf4jDependencies - - providedCompile "javax.servlet:javax.servlet-api" - providedCompile "javax.servlet.jsp:javax.servlet.jsp-api" - - testCompile "junit:junit" - testCompile "org.assertj:assertj-core" - - integrationTestCompile seleniumDependencies -} diff --git a/samples/javaconfig/hazelcast/src/integration-test/java/sample/HazelcastSpringTests.java b/samples/javaconfig/hazelcast/src/integration-test/java/sample/HazelcastSpringTests.java deleted file mode 100644 index 4aeeb04..0000000 --- a/samples/javaconfig/hazelcast/src/integration-test/java/sample/HazelcastSpringTests.java +++ /dev/null @@ -1,60 +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.htmlunit.HtmlUnitDriver; -import sample.pages.HomePage; -import sample.pages.LoginPage; - -/** - * @author Eddú Meléndez - * @author Rob Winch - */ -public class HazelcastSpringTests { - - private WebDriver driver; - - @Before - public void setup() { - this.driver = new HtmlUnitDriver(); - } - - @After - public void tearDown() { - this.driver.quit(); - } - - @Test - public void goHomeRedirectLoginPage() { - LoginPage login = HomePage.go(this.driver); - login.assertAt(); - } - - @Test - public void login() { - LoginPage login = HomePage.go(this.driver); - login.assertAt(); - HomePage home = login.form().login(HomePage.class); - home.containCookie("SESSION"); - home.doesNotContainCookie("JSESSIONID"); - } - -} diff --git a/samples/javaconfig/hazelcast/src/integration-test/java/sample/pages/BasePage.java b/samples/javaconfig/hazelcast/src/integration-test/java/sample/pages/BasePage.java deleted file mode 100644 index 6171813..0000000 --- a/samples/javaconfig/hazelcast/src/integration-test/java/sample/pages/BasePage.java +++ /dev/null @@ -1,42 +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; - -/** - * @author Eddú Meléndez - * @author Rob Winch - */ -public 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", "8080"); - driver.get(baseUrl + get); - } - -} diff --git a/samples/javaconfig/hazelcast/src/integration-test/java/sample/pages/HomePage.java b/samples/javaconfig/hazelcast/src/integration-test/java/sample/pages/HomePage.java deleted file mode 100644 index 61b3694..0000000 --- a/samples/javaconfig/hazelcast/src/integration-test/java/sample/pages/HomePage.java +++ /dev/null @@ -1,55 +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 java.util.Set; - -import org.openqa.selenium.Cookie; -import org.openqa.selenium.WebDriver; -import org.openqa.selenium.support.PageFactory; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Eddú Meléndez - */ -public class HomePage extends BasePage { - - public HomePage(WebDriver driver) { - super(driver); - } - - public static LoginPage go(WebDriver driver) { - get(driver, "/"); - return PageFactory.initElements(driver, LoginPage.class); - } - - public void assertAt() { - assertThat(getDriver().getTitle()).isEqualTo("Secured Content"); - } - - public void containCookie(String cookieName) { - Set cookies = getDriver().manage().getCookies(); - assertThat(cookies).extracting("name").contains(cookieName); - } - - public void doesNotContainCookie(String cookieName) { - Set cookies = getDriver().manage().getCookies(); - assertThat(cookies).extracting("name").doesNotContain(cookieName); - } - -} diff --git a/samples/javaconfig/hazelcast/src/integration-test/java/sample/pages/LoginPage.java b/samples/javaconfig/hazelcast/src/integration-test/java/sample/pages/LoginPage.java deleted file mode 100644 index e3e89f3..0000000 --- a/samples/javaconfig/hazelcast/src/integration-test/java/sample/pages/LoginPage.java +++ /dev/null @@ -1,69 +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.SearchContext; -import org.openqa.selenium.WebDriver; -import org.openqa.selenium.WebElement; -import org.openqa.selenium.support.FindBy; -import org.openqa.selenium.support.PageFactory; -import org.openqa.selenium.support.pagefactory.DefaultElementLocatorFactory; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Eddú Meléndez - * @author Rob Winch - */ -public class LoginPage extends BasePage { - - public LoginPage(WebDriver driver) { - super(driver); - } - - public void assertAt() { - assertThat(getDriver().getTitle()).isEqualTo("Login Page"); - } - - public Form form() { - return new Form(getDriver()); - } - - public class Form { - - @FindBy(name = "username") - private WebElement username; - - @FindBy(name = "password") - private WebElement password; - - @FindBy(name = "submit") - private WebElement button; - - public Form(SearchContext context) { - PageFactory.initElements(new DefaultElementLocatorFactory(context), this); - } - - public T login(Class page) { - this.username.sendKeys("user"); - this.password.sendKeys("password"); - this.button.click(); - return PageFactory.initElements(getDriver(), page); - } - } - -} diff --git a/samples/javaconfig/hazelcast/src/main/java/sample/Initializer.java b/samples/javaconfig/hazelcast/src/main/java/sample/Initializer.java deleted file mode 100644 index 6970e50..0000000 --- a/samples/javaconfig/hazelcast/src/main/java/sample/Initializer.java +++ /dev/null @@ -1,25 +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 org.springframework.session.web.context.AbstractHttpSessionApplicationInitializer; - -// tag::class[] -public class Initializer extends AbstractHttpSessionApplicationInitializer { - -} -// end::class[] diff --git a/samples/javaconfig/hazelcast/src/main/java/sample/ObjectStreamSerializer.java b/samples/javaconfig/hazelcast/src/main/java/sample/ObjectStreamSerializer.java deleted file mode 100644 index 1e9149f..0000000 --- a/samples/javaconfig/hazelcast/src/main/java/sample/ObjectStreamSerializer.java +++ /dev/null @@ -1,63 +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 java.io.InputStream; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.OutputStream; - -import com.hazelcast.nio.ObjectDataInput; -import com.hazelcast.nio.ObjectDataOutput; -import com.hazelcast.nio.serialization.StreamSerializer; - -/** - * A {@link StreamSerializer} that uses Java serialization to persist the session. This is - * certainly not the most efficient way to persist sessions, but the example is intended - * to demonstrate using minimal dependencies. For better serialization methods try using - * Kryo. - * - * @author Rob Winch - * - */ -public class ObjectStreamSerializer implements StreamSerializer { - public int getTypeId() { - return 2; - } - - public void write(ObjectDataOutput objectDataOutput, Object object) - throws IOException { - ObjectOutputStream out = new ObjectOutputStream((OutputStream) objectDataOutput); - out.writeObject(object); - out.flush(); - } - - public Object read(ObjectDataInput objectDataInput) throws IOException { - ObjectInputStream in = new ObjectInputStream((InputStream) objectDataInput); - try { - return in.readObject(); - } - catch (ClassNotFoundException e) { - throw new IOException(e); - } - } - - public void destroy() { - } - -} diff --git a/samples/javaconfig/hazelcast/src/main/java/sample/SecurityConfig.java b/samples/javaconfig/hazelcast/src/main/java/sample/SecurityConfig.java deleted file mode 100644 index 78b0788..0000000 --- a/samples/javaconfig/hazelcast/src/main/java/sample/SecurityConfig.java +++ /dev/null @@ -1,33 +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; - -/** - * @author Rob Winch - */ - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; - -@EnableWebSecurity -public class SecurityConfig { - @Autowired - public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { - auth.inMemoryAuthentication().withUser("user").password("password").roles("USER"); - } -} diff --git a/samples/javaconfig/hazelcast/src/main/java/sample/SecurityInitializer.java b/samples/javaconfig/hazelcast/src/main/java/sample/SecurityInitializer.java deleted file mode 100644 index 36f8611..0000000 --- a/samples/javaconfig/hazelcast/src/main/java/sample/SecurityInitializer.java +++ /dev/null @@ -1,28 +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 org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer; - -// tag::class[] -public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer { - - public SecurityInitializer() { - super(SecurityConfig.class, SessionConfig.class); - } -} -// end::class[] diff --git a/samples/javaconfig/hazelcast/src/main/java/sample/SessionConfig.java b/samples/javaconfig/hazelcast/src/main/java/sample/SessionConfig.java deleted file mode 100644 index 1451d09..0000000 --- a/samples/javaconfig/hazelcast/src/main/java/sample/SessionConfig.java +++ /dev/null @@ -1,69 +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 com.hazelcast.config.Config; -import com.hazelcast.config.MapAttributeConfig; -import com.hazelcast.config.MapIndexConfig; -import com.hazelcast.config.SerializerConfig; -import com.hazelcast.core.Hazelcast; -import com.hazelcast.core.HazelcastInstance; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.session.hazelcast.HazelcastSessionRepository; -import org.springframework.session.hazelcast.PrincipalNameExtractor; -import org.springframework.session.hazelcast.config.annotation.web.http.EnableHazelcastHttpSession; -import org.springframework.util.SocketUtils; - -// tag::class[] -@EnableHazelcastHttpSession(maxInactiveIntervalInSeconds = 300) -@Configuration -public class SessionConfig { - - @Bean(destroyMethod = "shutdown") - public HazelcastInstance hazelcastInstance() { - Config config = new Config(); - - int port = SocketUtils.findAvailableTcpPort(); - - config.getNetworkConfig() - .setPort(port); - - System.out.println("Hazelcast port #: " + port); - - SerializerConfig serializer = new SerializerConfig() - .setImplementation(new ObjectStreamSerializer()) - .setTypeClass(Object.class); - - config.getSerializationConfig() - .addSerializerConfig(serializer); - - MapAttributeConfig attributeConfig = new MapAttributeConfig() - .setName(HazelcastSessionRepository.PRINCIPAL_NAME_ATTRIBUTE) - .setExtractor(PrincipalNameExtractor.class.getName()); - - config.getMapConfig("spring:session:sessions") - .addMapAttributeConfig(attributeConfig) - .addMapIndexConfig(new MapIndexConfig( - HazelcastSessionRepository.PRINCIPAL_NAME_ATTRIBUTE, false)); - - return Hazelcast.newHazelcastInstance(config); - } - -} -// end::class[] diff --git a/samples/javaconfig/hazelcast/src/main/java/sample/SessionServlet.java b/samples/javaconfig/hazelcast/src/main/java/sample/SessionServlet.java deleted file mode 100644 index 8b78787..0000000 --- a/samples/javaconfig/hazelcast/src/main/java/sample/SessionServlet.java +++ /dev/null @@ -1,40 +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("/session") -public class SessionServlet extends HttpServlet { - - @Override - protected void doPost(HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException { - String attributeName = req.getParameter("attributeName"); - String attributeValue = req.getParameter("attributeValue"); - req.getSession().setAttribute(attributeName, attributeValue); - resp.sendRedirect(req.getContextPath() + "/"); - } - - private static final long serialVersionUID = 2878267318695777395L; -} diff --git a/samples/javaconfig/hazelcast/src/main/webapp/META-INF/MANIFEST.MF b/samples/javaconfig/hazelcast/src/main/webapp/META-INF/MANIFEST.MF deleted file mode 100644 index e69de29..0000000 diff --git a/samples/javaconfig/hazelcast/src/main/webapp/index.jsp b/samples/javaconfig/hazelcast/src/main/webapp/index.jsp deleted file mode 100644 index 5794eab..0000000 --- a/samples/javaconfig/hazelcast/src/main/webapp/index.jsp +++ /dev/null @@ -1,34 +0,0 @@ -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> -<%@ taglib prefix="wj" uri="http://www.webjars.org/tags" %> - - - - Secured Content - - "> - - - -
-

Description

-

This demonstrates how Spring Session and Hazelcast can be combined with Spring Security. The important thing to ensure is that Spring Session's Filter is included before Spring Security's Filter.

- -

Logged in as

- -

You are currently logged in as .

- - -
- - -
-
- - diff --git a/samples/javaconfig/jdbc/spring-session-sample-javaconfig-jdbc.gradle b/samples/javaconfig/jdbc/spring-session-sample-javaconfig-jdbc.gradle deleted file mode 100644 index 326e690..0000000 --- a/samples/javaconfig/jdbc/spring-session-sample-javaconfig-jdbc.gradle +++ /dev/null @@ -1,18 +0,0 @@ -apply plugin: 'io.spring.convention.spring-sample-war' - -dependencies { - compile project(':spring-session-jdbc') - compile "org.springframework:spring-web" - compile "org.webjars:bootstrap" - compile "org.webjars:webjars-taglib" - compile "com.h2database:h2" - compile jstlDependencies - compile slf4jDependencies - - providedCompile "javax.servlet:javax.servlet-api" - - testCompile "junit:junit" - testCompile "org.assertj:assertj-core" - - integrationTestCompile seleniumDependencies -} diff --git a/samples/javaconfig/jdbc/src/integration-test/java/sample/AttributeTests.java b/samples/javaconfig/jdbc/src/integration-test/java/sample/AttributeTests.java deleted file mode 100644 index 97b8342..0000000 --- a/samples/javaconfig/jdbc/src/integration-test/java/sample/AttributeTests.java +++ /dev/null @@ -1,78 +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.util.List; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.openqa.selenium.WebDriver; -import org.openqa.selenium.htmlunit.HtmlUnitDriver; -import sample.pages.HomePage; -import sample.pages.HomePage.Attribute; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Eddú Meléndez - * @author Rob Winch - */ -public class AttributeTests { - - private WebDriver driver; - - @Before - public void setup() { - this.driver = new HtmlUnitDriver(); - } - - @After - public void tearDown() { - this.driver.quit(); - } - - @Test - public void home() { - HomePage home = HomePage.go(this.driver); - home.assertAt(); - } - - @Test - public void noAttributes() { - HomePage home = HomePage.go(this.driver); - assertThat(home.attributes()).isEmpty(); - } - - @Test - public void createAttribute() { - HomePage home = HomePage.go(this.driver); - // @formatter:off - home = home.form() - .attributeName("a") - .attributeValue("b") - .submit(HomePage.class); - // @formatter:on - - List attributes = home.attributes(); - assertThat(attributes).hasSize(1); - Attribute row = attributes.get(0); - assertThat(row.getAttributeName()).isEqualTo("a"); - assertThat(row.getAttributeValue()).isEqualTo("b"); - } - -} diff --git a/samples/javaconfig/jdbc/src/integration-test/java/sample/pages/HomePage.java b/samples/javaconfig/jdbc/src/integration-test/java/sample/pages/HomePage.java deleted file mode 100644 index e9e0134..0000000 --- a/samples/javaconfig/jdbc/src/integration-test/java/sample/pages/HomePage.java +++ /dev/null @@ -1,135 +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 java.util.ArrayList; -import java.util.List; - -import org.openqa.selenium.SearchContext; -import org.openqa.selenium.WebDriver; -import org.openqa.selenium.WebElement; -import org.openqa.selenium.support.FindBy; -import org.openqa.selenium.support.PageFactory; -import org.openqa.selenium.support.pagefactory.DefaultElementLocatorFactory; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Eddú Meléndez - * @author Rob Winch - */ -public class HomePage { - - private WebDriver driver; - - @FindBy(css = "form") - WebElement form; - - @FindBy(css = "table tbody tr") - List trs; - - List attributes; - - public HomePage(WebDriver driver) { - this.driver = driver; - this.attributes = new ArrayList(); - } - - private static void get(WebDriver driver, String get) { - String baseUrl = "http://localhost:" + System.getProperty("app.port", "8080"); - driver.get(baseUrl + get); - } - - public static HomePage go(WebDriver driver) { - get(driver, "/"); - return PageFactory.initElements(driver, HomePage.class); - } - - public void assertAt() { - assertThat(this.driver.getTitle()).isEqualTo("Session Attributes"); - } - - public List attributes() { - List rows = new ArrayList(); - for (WebElement tr : this.trs) { - rows.add(new Attribute(tr)); - } - this.attributes.addAll(rows); - return this.attributes; - } - - public Form form() { - return new Form(this.form); - } - - public class Form { - @FindBy(name = "attributeName") - WebElement attributeName; - - @FindBy(name = "attributeValue") - WebElement attributeValue; - - @FindBy(css = "input[type=\"submit\"]") - WebElement submit; - - public Form(SearchContext context) { - PageFactory.initElements(new DefaultElementLocatorFactory(context), this); - } - - public Form attributeName(String text) { - this.attributeName.sendKeys(text); - return this; - } - - public Form attributeValue(String text) { - this.attributeValue.sendKeys(text); - return this; - } - - public T submit(Class page) { - this.submit.click(); - return PageFactory.initElements(HomePage.this.driver, page); - } - } - - public static class Attribute { - @FindBy(xpath = ".//td[1]") - WebElement attributeName; - - @FindBy(xpath = ".//td[2]") - WebElement attributeValue; - - public Attribute(SearchContext context) { - PageFactory.initElements(new DefaultElementLocatorFactory(context), this); - } - - /** - * @return the attributeName - */ - public String getAttributeName() { - return this.attributeName.getText(); - } - - /** - * @return the attributeValue - */ - public String getAttributeValue() { - return this.attributeValue.getText(); - } - } - -} diff --git a/samples/javaconfig/jdbc/src/main/java/sample/Config.java b/samples/javaconfig/jdbc/src/main/java/sample/Config.java deleted file mode 100644 index 7692ec7..0000000 --- a/samples/javaconfig/jdbc/src/main/java/sample/Config.java +++ /dev/null @@ -1,46 +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.sql.DataSource; - -import org.springframework.context.annotation.Bean; -import org.springframework.jdbc.datasource.DataSourceTransactionManager; -import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase; -import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; -import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; -import org.springframework.session.jdbc.config.annotation.web.http.EnableJdbcHttpSession; -import org.springframework.transaction.PlatformTransactionManager; - -// tag::class[] -@EnableJdbcHttpSession // <1> -public class Config { - - @Bean - public EmbeddedDatabase dataSource() { - return new EmbeddedDatabaseBuilder() // <2> - .setType(EmbeddedDatabaseType.H2) - .addScript("org/springframework/session/jdbc/schema-h2.sql").build(); - } - - @Bean - public PlatformTransactionManager transactionManager(DataSource dataSource) { - return new DataSourceTransactionManager(dataSource); // <3> - } - -} -// end::class[] diff --git a/samples/javaconfig/jdbc/src/main/java/sample/H2ConsoleInitializer.java b/samples/javaconfig/jdbc/src/main/java/sample/H2ConsoleInitializer.java deleted file mode 100644 index 7229e7e..0000000 --- a/samples/javaconfig/jdbc/src/main/java/sample/H2ConsoleInitializer.java +++ /dev/null @@ -1,31 +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 javax.servlet.ServletException; - -import org.h2.server.web.WebServlet; - -import org.springframework.web.WebApplicationInitializer; - -public class H2ConsoleInitializer implements WebApplicationInitializer { - - public void onStartup(ServletContext servletContext) throws ServletException { - servletContext.addServlet("h2Console", new WebServlet()).addMapping("/h2-console/*"); - } - -} diff --git a/samples/javaconfig/jdbc/src/main/java/sample/Initializer.java b/samples/javaconfig/jdbc/src/main/java/sample/Initializer.java deleted file mode 100644 index f31c6eb..0000000 --- a/samples/javaconfig/jdbc/src/main/java/sample/Initializer.java +++ /dev/null @@ -1,27 +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 org.springframework.session.web.context.AbstractHttpSessionApplicationInitializer; - -// tag::class[] -public class Initializer extends AbstractHttpSessionApplicationInitializer { // <1> - - public Initializer() { - super(Config.class); // <2> - } -} -// end::class[] diff --git a/samples/javaconfig/jdbc/src/main/java/sample/SessionServlet.java b/samples/javaconfig/jdbc/src/main/java/sample/SessionServlet.java deleted file mode 100644 index 2fa5cea..0000000 --- a/samples/javaconfig/jdbc/src/main/java/sample/SessionServlet.java +++ /dev/null @@ -1,41 +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; - -// tag::class[] -@WebServlet("/session") -public class SessionServlet extends HttpServlet { - - @Override - protected void doPost(HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException { - String attributeName = req.getParameter("attributeName"); - String attributeValue = req.getParameter("attributeValue"); - req.getSession().setAttribute(attributeName, attributeValue); - resp.sendRedirect(req.getContextPath() + "/"); - } - - private static final long serialVersionUID = 2878267318695777395L; -} -// tag::end[] diff --git a/samples/javaconfig/jdbc/src/main/webapp/META-INF/MANIFEST.MF b/samples/javaconfig/jdbc/src/main/webapp/META-INF/MANIFEST.MF deleted file mode 100644 index e69de29..0000000 diff --git a/samples/javaconfig/jdbc/src/main/webapp/index.jsp b/samples/javaconfig/jdbc/src/main/webapp/index.jsp deleted file mode 100644 index 134d930..0000000 --- a/samples/javaconfig/jdbc/src/main/webapp/index.jsp +++ /dev/null @@ -1,50 +0,0 @@ -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> -<%@ taglib prefix="wj" uri="http://www.webjars.org/tags" %> - - - - Session Attributes - - "> - - - -
-

Description

-

This application demonstrates how to use a relational database to back your session. Notice that there is no JSESSIONID cookie. We are also able to customize the way of identifying what the requested session id is.

- -

Try it

- -
- - - - - -
- -
- - - - - - - - - - - - - - - - -
Attribute NameAttribute Value
-
- - diff --git a/samples/javaconfig/redis/spring-session-sample-javaconfig-redis.gradle b/samples/javaconfig/redis/spring-session-sample-javaconfig-redis.gradle deleted file mode 100644 index bc4d612..0000000 --- a/samples/javaconfig/redis/spring-session-sample-javaconfig-redis.gradle +++ /dev/null @@ -1,20 +0,0 @@ -apply plugin: 'io.spring.convention.spring-sample-war' - -dependencies { - compile(project(':spring-session-data-redis')) { - exclude module: 'jedis' - } - compile "org.springframework:spring-web" - compile "io.lettuce:lettuce-core" - compile "org.webjars:bootstrap" - compile "org.webjars:webjars-taglib" - compile jstlDependencies - compile slf4jDependencies - - providedCompile "javax.servlet:javax.servlet-api" - - testCompile "junit:junit" - testCompile "org.assertj:assertj-core" - - integrationTestCompile seleniumDependencies -} diff --git a/samples/javaconfig/redis/src/integration-test/java/sample/AttributeTests.java b/samples/javaconfig/redis/src/integration-test/java/sample/AttributeTests.java deleted file mode 100644 index 97b8342..0000000 --- a/samples/javaconfig/redis/src/integration-test/java/sample/AttributeTests.java +++ /dev/null @@ -1,78 +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.util.List; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.openqa.selenium.WebDriver; -import org.openqa.selenium.htmlunit.HtmlUnitDriver; -import sample.pages.HomePage; -import sample.pages.HomePage.Attribute; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Eddú Meléndez - * @author Rob Winch - */ -public class AttributeTests { - - private WebDriver driver; - - @Before - public void setup() { - this.driver = new HtmlUnitDriver(); - } - - @After - public void tearDown() { - this.driver.quit(); - } - - @Test - public void home() { - HomePage home = HomePage.go(this.driver); - home.assertAt(); - } - - @Test - public void noAttributes() { - HomePage home = HomePage.go(this.driver); - assertThat(home.attributes()).isEmpty(); - } - - @Test - public void createAttribute() { - HomePage home = HomePage.go(this.driver); - // @formatter:off - home = home.form() - .attributeName("a") - .attributeValue("b") - .submit(HomePage.class); - // @formatter:on - - List attributes = home.attributes(); - assertThat(attributes).hasSize(1); - Attribute row = attributes.get(0); - assertThat(row.getAttributeName()).isEqualTo("a"); - assertThat(row.getAttributeValue()).isEqualTo("b"); - } - -} diff --git a/samples/javaconfig/redis/src/integration-test/java/sample/pages/HomePage.java b/samples/javaconfig/redis/src/integration-test/java/sample/pages/HomePage.java deleted file mode 100644 index e9e0134..0000000 --- a/samples/javaconfig/redis/src/integration-test/java/sample/pages/HomePage.java +++ /dev/null @@ -1,135 +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 java.util.ArrayList; -import java.util.List; - -import org.openqa.selenium.SearchContext; -import org.openqa.selenium.WebDriver; -import org.openqa.selenium.WebElement; -import org.openqa.selenium.support.FindBy; -import org.openqa.selenium.support.PageFactory; -import org.openqa.selenium.support.pagefactory.DefaultElementLocatorFactory; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Eddú Meléndez - * @author Rob Winch - */ -public class HomePage { - - private WebDriver driver; - - @FindBy(css = "form") - WebElement form; - - @FindBy(css = "table tbody tr") - List trs; - - List attributes; - - public HomePage(WebDriver driver) { - this.driver = driver; - this.attributes = new ArrayList(); - } - - private static void get(WebDriver driver, String get) { - String baseUrl = "http://localhost:" + System.getProperty("app.port", "8080"); - driver.get(baseUrl + get); - } - - public static HomePage go(WebDriver driver) { - get(driver, "/"); - return PageFactory.initElements(driver, HomePage.class); - } - - public void assertAt() { - assertThat(this.driver.getTitle()).isEqualTo("Session Attributes"); - } - - public List attributes() { - List rows = new ArrayList(); - for (WebElement tr : this.trs) { - rows.add(new Attribute(tr)); - } - this.attributes.addAll(rows); - return this.attributes; - } - - public Form form() { - return new Form(this.form); - } - - public class Form { - @FindBy(name = "attributeName") - WebElement attributeName; - - @FindBy(name = "attributeValue") - WebElement attributeValue; - - @FindBy(css = "input[type=\"submit\"]") - WebElement submit; - - public Form(SearchContext context) { - PageFactory.initElements(new DefaultElementLocatorFactory(context), this); - } - - public Form attributeName(String text) { - this.attributeName.sendKeys(text); - return this; - } - - public Form attributeValue(String text) { - this.attributeValue.sendKeys(text); - return this; - } - - public T submit(Class page) { - this.submit.click(); - return PageFactory.initElements(HomePage.this.driver, page); - } - } - - public static class Attribute { - @FindBy(xpath = ".//td[1]") - WebElement attributeName; - - @FindBy(xpath = ".//td[2]") - WebElement attributeValue; - - public Attribute(SearchContext context) { - PageFactory.initElements(new DefaultElementLocatorFactory(context), this); - } - - /** - * @return the attributeName - */ - public String getAttributeName() { - return this.attributeName.getText(); - } - - /** - * @return the attributeValue - */ - public String getAttributeValue() { - return this.attributeValue.getText(); - } - } - -} diff --git a/samples/javaconfig/redis/src/main/java/sample/Config.java b/samples/javaconfig/redis/src/main/java/sample/Config.java deleted file mode 100644 index 4a03dd7..0000000 --- a/samples/javaconfig/redis/src/main/java/sample/Config.java +++ /dev/null @@ -1,32 +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 org.springframework.context.annotation.Bean; -import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; -import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession; - -// tag::class[] -@EnableRedisHttpSession // <1> -public class Config { - - @Bean - public LettuceConnectionFactory connectionFactory() { - return new LettuceConnectionFactory(); // <2> - } -} -// end::class[] diff --git a/samples/javaconfig/redis/src/main/java/sample/Initializer.java b/samples/javaconfig/redis/src/main/java/sample/Initializer.java deleted file mode 100644 index b7472d1..0000000 --- a/samples/javaconfig/redis/src/main/java/sample/Initializer.java +++ /dev/null @@ -1,28 +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 org.springframework.session.web.context.AbstractHttpSessionApplicationInitializer; - -// tag::class[] -public class Initializer extends AbstractHttpSessionApplicationInitializer { // <1> - - public Initializer() { - super(Config.class); // <2> - } -} -// end::class[] diff --git a/samples/javaconfig/redis/src/main/java/sample/SessionServlet.java b/samples/javaconfig/redis/src/main/java/sample/SessionServlet.java deleted file mode 100644 index 5e0a06f..0000000 --- a/samples/javaconfig/redis/src/main/java/sample/SessionServlet.java +++ /dev/null @@ -1,42 +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; - -// tag::class[] -@WebServlet("/session") -public class SessionServlet extends HttpServlet { - - @Override - protected void doPost(HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException { - String attributeName = req.getParameter("attributeName"); - String attributeValue = req.getParameter("attributeValue"); - req.getSession().setAttribute(attributeName, attributeValue); - resp.sendRedirect(req.getContextPath() + "/"); - } - - private static final long serialVersionUID = 2878267318695777395L; -} -// tag::end[] diff --git a/samples/javaconfig/redis/src/main/webapp/META-INF/MANIFEST.MF b/samples/javaconfig/redis/src/main/webapp/META-INF/MANIFEST.MF deleted file mode 100644 index e69de29..0000000 diff --git a/samples/javaconfig/redis/src/main/webapp/index.jsp b/samples/javaconfig/redis/src/main/webapp/index.jsp deleted file mode 100644 index 8a273e5..0000000 --- a/samples/javaconfig/redis/src/main/webapp/index.jsp +++ /dev/null @@ -1,50 +0,0 @@ -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> -<%@ taglib prefix="wj" uri="http://www.webjars.org/tags" %> - - - - Session Attributes - - "> - - - -
-

Description

-

This application demonstrates how to use a Redis instance to back your session. Notice that there is no JSESSIONID cookie. We are also able to customize the way of identifying what the requested session id is.

- -

Try it

- -
- - - - - -
- -
- - - - - - - - - - - - - - - - -
Attribute NameAttribute Value
-
- - diff --git a/samples/javaconfig/rest/spring-session-sample-javaconfig-rest.gradle b/samples/javaconfig/rest/spring-session-sample-javaconfig-rest.gradle deleted file mode 100644 index 7e50bf8..0000000 --- a/samples/javaconfig/rest/spring-session-sample-javaconfig-rest.gradle +++ /dev/null @@ -1,22 +0,0 @@ -apply plugin: 'io.spring.convention.spring-sample-war' - -dependencies { - compile(project(':spring-session-data-redis')) { - exclude module: 'jedis' - } - compile "io.lettuce:lettuce-core" - compile "org.springframework:spring-webmvc" - compile "org.springframework.security:spring-security-config" - compile "org.springframework.security:spring-security-web" - compile "com.fasterxml.jackson.core:jackson-databind" - compile jstlDependencies - compile slf4jDependencies - - providedCompile "javax.servlet:javax.servlet-api" - - testCompile "junit:junit" - testCompile "org.springframework.security:spring-security-test" - testCompile "org.assertj:assertj-core" - testCompile "org.springframework:spring-test" - testCompile "commons-codec:commons-codec" -} \ No newline at end of file diff --git a/samples/javaconfig/rest/src/integration-test/java/rest/RestMockMvcTests.java b/samples/javaconfig/rest/src/integration-test/java/rest/RestMockMvcTests.java deleted file mode 100644 index ec9e1a1..0000000 --- a/samples/javaconfig/rest/src/integration-test/java/rest/RestMockMvcTests.java +++ /dev/null @@ -1,84 +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 rest; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -import sample.HttpSessionConfig; -import sample.SecurityConfig; -import sample.mvc.MvcConfig; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.test.context.support.WithMockUser; -import org.springframework.session.ExpiringSession; -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 org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import org.springframework.web.context.WebApplicationContext; - -import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user; -import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(classes = { HttpSessionConfig.class, SecurityConfig.class, - MvcConfig.class }) -@WebAppConfiguration -public class RestMockMvcTests { - - @Autowired - SessionRepositoryFilter sessionRepositoryFilter; - - @Autowired - WebApplicationContext context; - - MockMvc mvc; - - @Before - public void setup() { - this.mvc = MockMvcBuilders.webAppContextSetup(this.context).alwaysDo(print()) - .addFilters(this.sessionRepositoryFilter).apply(springSecurity()).build(); - } - - @Test - public void noSessionOnNoCredentials() throws Exception { - this.mvc.perform(get("/")).andExpect(header().doesNotExist("X-Auth-Token")) - .andExpect(status().isUnauthorized()); - } - - @WithMockUser - @Test - public void autheticatedAnnotation() throws Exception { - this.mvc.perform(get("/")).andExpect(content().string("{\"username\":\"user\"}")); - } - - @Test - public void autheticatedRequestPostProcessor() throws Exception { - this.mvc.perform(get("/").with(user("user"))) - .andExpect(content().string("{\"username\":\"user\"}")); - } - -} diff --git a/samples/javaconfig/rest/src/integration-test/java/sample/RestTests.java b/samples/javaconfig/rest/src/integration-test/java/sample/RestTests.java deleted file mode 100644 index e12c763..0000000 --- a/samples/javaconfig/rest/src/integration-test/java/sample/RestTests.java +++ /dev/null @@ -1,127 +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.util.Arrays; - -import org.apache.commons.codec.binary.Base64; -import org.junit.Before; -import org.junit.Test; - -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; -import org.springframework.web.client.HttpClientErrorException; -import org.springframework.web.client.RestTemplate; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Pool Dolorier - */ -public class RestTests { - - private static final String AUTHORIZATION = "Authorization"; - private static final String BASIC = "Basic "; - private static final String X_AUTH_TOKEN = "X-Auth-Token"; - - private RestTemplate restTemplate; - - private String baseUrl; - - @Before - public void setUp() { - this.baseUrl = "http://localhost:" + System.getProperty("app.port"); - this.restTemplate = new RestTemplate(); - } - - @Test(expected = HttpClientErrorException.class) - public void unauthenticatedUserSentToLogInPage() { - HttpHeaders headers = new HttpHeaders(); - headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON)); - ResponseEntity entity = getForUser(this.baseUrl + "/", - headers, String.class); - assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED); - } - - @Test - public void authenticateWithBasicWorks() { - String auth = getAuth("user", "password"); - HttpHeaders headers = getHttpHeaders(); - headers.set(AUTHORIZATION, BASIC + auth); - ResponseEntity entity = getForUser(this.baseUrl + "/", - headers, User.class); - assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK); - assertThat(entity.getHeaders().containsKey(X_AUTH_TOKEN)).isTrue(); - assertThat(entity.getBody().getUsername()).isEqualTo("user"); - } - - @Test - public void authenticateWithXAuthTokenWorks() { - String auth = getAuth("user", "password"); - HttpHeaders headers = getHttpHeaders(); - headers.set(AUTHORIZATION, BASIC + auth); - ResponseEntity entity = getForUser(this.baseUrl + "/", - headers, User.class); - - String token = entity.getHeaders().getFirst(X_AUTH_TOKEN); - - HttpHeaders authTokenHeader = new HttpHeaders(); - authTokenHeader.setAccept(Arrays.asList(MediaType.APPLICATION_JSON)); - authTokenHeader.set(X_AUTH_TOKEN, token); - ResponseEntity authTokenResponse = getForUser(this.baseUrl + "/", - authTokenHeader, User.class); - assertThat(authTokenResponse.getStatusCode()).isEqualTo(HttpStatus.OK); - assertThat(authTokenResponse.getBody().getUsername()).isEqualTo("user"); - } - - @Test - public void logout() { - String auth = getAuth("user", "password"); - HttpHeaders headers = getHttpHeaders(); - headers.set(AUTHORIZATION, BASIC + auth); - ResponseEntity entity = getForUser(this.baseUrl + "/", - headers, User.class); - - String token = entity.getHeaders().getFirst(X_AUTH_TOKEN); - - HttpHeaders logoutHeader = getHttpHeaders(); - logoutHeader.set(X_AUTH_TOKEN, token); - ResponseEntity logoutResponse = getForUser(this.baseUrl + "/logout", - logoutHeader, User.class); - assertThat(logoutResponse.getStatusCode()).isEqualTo(HttpStatus.NO_CONTENT); - } - - private ResponseEntity getForUser(String resourceUrl, HttpHeaders headers, Class type) { - return this.restTemplate.exchange(resourceUrl, - HttpMethod.GET, new HttpEntity(headers), type); - } - - private HttpHeaders getHttpHeaders() { - HttpHeaders headers = new HttpHeaders(); - headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON)); - return headers; - } - - private String getAuth(String user, String password) { - String auth = user + ":" + password; - return new String(Base64.encodeBase64(auth.getBytes())); - } -} diff --git a/samples/javaconfig/rest/src/integration-test/java/sample/User.java b/samples/javaconfig/rest/src/integration-test/java/sample/User.java deleted file mode 100644 index 9f4052e..0000000 --- a/samples/javaconfig/rest/src/integration-test/java/sample/User.java +++ /dev/null @@ -1,33 +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; - -/** - * @author Pool Dolorier - */ -public class User { - - private String username; - - public String getUsername() { - return this.username; - } - - public void setUsername(String username) { - this.username = username; - } -} diff --git a/samples/javaconfig/rest/src/main/java/sample/HttpSessionConfig.java b/samples/javaconfig/rest/src/main/java/sample/HttpSessionConfig.java deleted file mode 100644 index 5fc10a6..0000000 --- a/samples/javaconfig/rest/src/main/java/sample/HttpSessionConfig.java +++ /dev/null @@ -1,41 +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 org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; -import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession; -import org.springframework.session.web.http.HeaderHttpSessionStrategy; -import org.springframework.session.web.http.HttpSessionStrategy; - -// tag::class[] -@Configuration -@EnableRedisHttpSession // <1> -public class HttpSessionConfig { - - @Bean - public LettuceConnectionFactory connectionFactory() { - return new LettuceConnectionFactory(); // <2> - } - - @Bean - public HttpSessionStrategy httpSessionStrategy() { - return new HeaderHttpSessionStrategy(); // <3> - } -} -// end::class[] diff --git a/samples/javaconfig/rest/src/main/java/sample/Initializer.java b/samples/javaconfig/rest/src/main/java/sample/Initializer.java deleted file mode 100644 index 6970e50..0000000 --- a/samples/javaconfig/rest/src/main/java/sample/Initializer.java +++ /dev/null @@ -1,25 +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 org.springframework.session.web.context.AbstractHttpSessionApplicationInitializer; - -// tag::class[] -public class Initializer extends AbstractHttpSessionApplicationInitializer { - -} -// end::class[] diff --git a/samples/javaconfig/rest/src/main/java/sample/SecurityConfig.java b/samples/javaconfig/rest/src/main/java/sample/SecurityConfig.java deleted file mode 100644 index dc452d1..0000000 --- a/samples/javaconfig/rest/src/main/java/sample/SecurityConfig.java +++ /dev/null @@ -1,51 +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 org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; -import org.springframework.security.web.savedrequest.NullRequestCache; - -@EnableWebSecurity -public class SecurityConfig extends WebSecurityConfigurerAdapter { - - // @formatter:off - @Override - protected void configure(HttpSecurity http) throws Exception { - http - .authorizeRequests() - .anyRequest().authenticated() - .and() - .requestCache() - .requestCache(new NullRequestCache()) - .and() - .httpBasic(); - } - // @formatter:on - - // @formatter:off - @Autowired - public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { - auth - .inMemoryAuthentication() - .withUser("user").password("password").roles("USER"); - } - // @formatter:on -} diff --git a/samples/javaconfig/rest/src/main/java/sample/SecurityInitializer.java b/samples/javaconfig/rest/src/main/java/sample/SecurityInitializer.java deleted file mode 100644 index 722f05a..0000000 --- a/samples/javaconfig/rest/src/main/java/sample/SecurityInitializer.java +++ /dev/null @@ -1,26 +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 org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer; - -/** - * @author Rob Winch - */ -public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer { - -} diff --git a/samples/javaconfig/rest/src/main/java/sample/mvc/MvcConfig.java b/samples/javaconfig/rest/src/main/java/sample/mvc/MvcConfig.java deleted file mode 100644 index 40842ec..0000000 --- a/samples/javaconfig/rest/src/main/java/sample/mvc/MvcConfig.java +++ /dev/null @@ -1,30 +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.mvc; - -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; -import org.springframework.web.servlet.config.annotation.EnableWebMvc; - -/** - * @author Rob Winch - */ -@Configuration -@EnableWebMvc -@ComponentScan -public class MvcConfig { -} diff --git a/samples/javaconfig/rest/src/main/java/sample/mvc/MvcInitializer.java b/samples/javaconfig/rest/src/main/java/sample/mvc/MvcInitializer.java deleted file mode 100644 index 26a61f7..0000000 --- a/samples/javaconfig/rest/src/main/java/sample/mvc/MvcInitializer.java +++ /dev/null @@ -1,44 +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.mvc; - -import sample.HttpSessionConfig; -import sample.SecurityConfig; - -import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; - -/** - * @author Rob Winch - */ -public class MvcInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { - // tag::config[] - @Override - protected Class[] getRootConfigClasses() { - return new Class[] { SecurityConfig.class, HttpSessionConfig.class }; - } - // end::config[] - - @Override - protected Class[] getServletConfigClasses() { - return new Class[] { MvcConfig.class }; - } - - @Override - protected String[] getServletMappings() { - return new String[] { "/" }; - } -} diff --git a/samples/javaconfig/rest/src/main/java/sample/mvc/RestDemoController.java b/samples/javaconfig/rest/src/main/java/sample/mvc/RestDemoController.java deleted file mode 100644 index 58e2a50..0000000 --- a/samples/javaconfig/rest/src/main/java/sample/mvc/RestDemoController.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.mvc; - -import java.security.Principal; -import java.util.HashMap; -import java.util.Map; - -import javax.servlet.http.HttpSession; - -import org.springframework.http.HttpStatus; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.ResponseStatus; -import org.springframework.web.bind.annotation.RestController; - -/** - * @author Rob Winch - */ -@RestController -public class RestDemoController { - - @RequestMapping(value = "/", produces = "application/json") - public Map helloUser(Principal principal) { - HashMap result = new HashMap(); - result.put("username", principal.getName()); - return result; - } - - @RequestMapping("/logout") - @ResponseStatus(HttpStatus.NO_CONTENT) - public void logout(HttpSession session) { - session.invalidate(); - } -} diff --git a/samples/javaconfig/rest/src/main/webapp/META-INF/MANIFEST.MF b/samples/javaconfig/rest/src/main/webapp/META-INF/MANIFEST.MF deleted file mode 100644 index e69de29..0000000 diff --git a/samples/javaconfig/security/spring-session-sample-javaconfig-security.gradle b/samples/javaconfig/security/spring-session-sample-javaconfig-security.gradle deleted file mode 100644 index 65dce5e..0000000 --- a/samples/javaconfig/security/spring-session-sample-javaconfig-security.gradle +++ /dev/null @@ -1,24 +0,0 @@ -apply plugin: 'io.spring.convention.spring-sample-war' - -dependencies { - compile(project(':spring-session-data-redis')) { - exclude module: 'jedis' - } - compile "org.springframework:spring-web" - compile "org.springframework.security:spring-security-config" - compile "org.springframework.security:spring-security-web" - compile "io.lettuce:lettuce-core" - compile "org.webjars:bootstrap" - compile "org.webjars:webjars-taglib" - compile jstlDependencies - compile slf4jDependencies - - providedCompile "javax.servlet:javax.servlet-api" - providedCompile "javax.servlet.jsp:javax.servlet.jsp-api" - - testCompile "junit:junit" - testCompile "org.assertj:assertj-core" - testCompile "org.springframework:spring-test" - - integrationTestCompile seleniumDependencies -} diff --git a/samples/javaconfig/security/src/integration-test/java/sample/SecurityTests.java b/samples/javaconfig/security/src/integration-test/java/sample/SecurityTests.java deleted file mode 100644 index bc58220..0000000 --- a/samples/javaconfig/security/src/integration-test/java/sample/SecurityTests.java +++ /dev/null @@ -1,88 +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.util.Set; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.openqa.selenium.By; -import org.openqa.selenium.Cookie; -import org.openqa.selenium.WebDriver; -import org.openqa.selenium.WebElement; -import org.openqa.selenium.htmlunit.HtmlUnitDriver; -import sample.pages.HomePage; -import sample.pages.LoginPage; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * - * @author Pool Dolorier - */ -public class SecurityTests { - - private WebDriver driver; - - @Before - public void setUp() { - this.driver = new HtmlUnitDriver(); - } - - @After - public void tearDown() { - this.driver.quit(); - } - - @Test - public void unauthenticatedUserSentToLogInPage() { - HomePage homePage = HomePage.go(this.driver); - LoginPage loginPage = homePage.unauthenticated(); - loginPage.assertAt(); - } - - @Test - public void logInViewsHomePage() { - LoginPage loginPage = LoginPage.go(this.driver); - HomePage homePage = loginPage.login("user", "password"); - homePage.assertAt(); - WebElement username = homePage.getDriver().findElement(By.id("un")); - assertThat(username.getText()).isEqualTo("user"); - Set cookies = homePage.getDriver().manage().getCookies(); - assertThat(cookies).extracting("name").contains("SESSION"); - assertThat(cookies).extracting("name").doesNotContain("JSESSIONID"); - } - - @Test - public void logOutSuccess() { - LoginPage loginPage = LoginPage.go(this.driver); - HomePage homePage = loginPage.login("user", "password"); - LoginPage successLogoutPage = homePage.logout(); - successLogoutPage.assertAt(); - } - - @Test - public void loggedOutUserSentToLoginPage() { - LoginPage loginPage = LoginPage.go(this.driver); - HomePage homePage = loginPage.login("user", "password"); - homePage.logout(); - HomePage backHomePage = HomePage.go(this.driver); - LoginPage backLoginPage = backHomePage.unauthenticated(); - backLoginPage.assertAt(); - } -} diff --git a/samples/javaconfig/security/src/integration-test/java/sample/pages/BasePage.java b/samples/javaconfig/security/src/integration-test/java/sample/pages/BasePage.java deleted file mode 100644 index 77933d9..0000000 --- a/samples/javaconfig/security/src/integration-test/java/sample/pages/BasePage.java +++ /dev/null @@ -1,41 +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; - -/** - * - * @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); - } -} diff --git a/samples/javaconfig/security/src/integration-test/java/sample/pages/HomePage.java b/samples/javaconfig/security/src/integration-test/java/sample/pages/HomePage.java deleted file mode 100644 index b8a46cf..0000000 --- a/samples/javaconfig/security/src/integration-test/java/sample/pages/HomePage.java +++ /dev/null @@ -1,55 +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(css = "input[type='submit']") - private WebElement button; - - public HomePage(WebDriver driver) { - super(driver); - } - - public static HomePage go(WebDriver driver) { - get(driver, "/"); - return PageFactory.initElements(driver, HomePage.class); - } - - public LoginPage unauthenticated() { - return LoginPage.go(getDriver()); - } - - public void assertAt() { - assertThat(getDriver().getTitle()).isEqualTo("Secured Content"); - } - - public LoginPage logout() { - this.button.click(); - return LoginPage.go(getDriver()); - } -} diff --git a/samples/javaconfig/security/src/integration-test/java/sample/pages/LoginPage.java b/samples/javaconfig/security/src/integration-test/java/sample/pages/LoginPage.java deleted file mode 100644 index 62db81b..0000000 --- a/samples/javaconfig/security/src/integration-test/java/sample/pages/LoginPage.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.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 LoginPage extends BasePage { - - @FindBy(name = "username") - private WebElement username; - - @FindBy(name = "password") - private WebElement password; - - @FindBy(css = "input[type='submit']") - private WebElement button; - - public LoginPage(WebDriver driver) { - super(driver); - } - - public static LoginPage go(WebDriver driver) { - get(driver, "/"); - return PageFactory.initElements(driver, LoginPage.class); - } - - public void assertAt() { - assertThat(getDriver().getTitle()).isEqualTo("Login Page"); - } - - public HomePage login(String user, String password) { - this.username.sendKeys(user); - this.password.sendKeys(password); - this.button.click(); - return HomePage.go(getDriver()); - } -} diff --git a/samples/javaconfig/security/src/main/java/sample/Config.java b/samples/javaconfig/security/src/main/java/sample/Config.java deleted file mode 100644 index 384e090..0000000 --- a/samples/javaconfig/security/src/main/java/sample/Config.java +++ /dev/null @@ -1,34 +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 org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; -import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession; - -// tag::class[] -@Configuration -@EnableRedisHttpSession // <1> -public class Config { - - @Bean - public LettuceConnectionFactory connectionFactory() { - return new LettuceConnectionFactory(); // <2> - } -} -// end::class[] diff --git a/samples/javaconfig/security/src/main/java/sample/Initializer.java b/samples/javaconfig/security/src/main/java/sample/Initializer.java deleted file mode 100644 index 6970e50..0000000 --- a/samples/javaconfig/security/src/main/java/sample/Initializer.java +++ /dev/null @@ -1,25 +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 org.springframework.session.web.context.AbstractHttpSessionApplicationInitializer; - -// tag::class[] -public class Initializer extends AbstractHttpSessionApplicationInitializer { - -} -// end::class[] diff --git a/samples/javaconfig/security/src/main/java/sample/SecurityConfig.java b/samples/javaconfig/security/src/main/java/sample/SecurityConfig.java deleted file mode 100644 index 78b0788..0000000 --- a/samples/javaconfig/security/src/main/java/sample/SecurityConfig.java +++ /dev/null @@ -1,33 +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; - -/** - * @author Rob Winch - */ - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; - -@EnableWebSecurity -public class SecurityConfig { - @Autowired - public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { - auth.inMemoryAuthentication().withUser("user").password("password").roles("USER"); - } -} diff --git a/samples/javaconfig/security/src/main/java/sample/SecurityInitializer.java b/samples/javaconfig/security/src/main/java/sample/SecurityInitializer.java deleted file mode 100644 index 76e3c51..0000000 --- a/samples/javaconfig/security/src/main/java/sample/SecurityInitializer.java +++ /dev/null @@ -1,28 +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 org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer; - -// tag::class[] -public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer { - - public SecurityInitializer() { - super(SecurityConfig.class, Config.class); - } -} -// end::class[] diff --git a/samples/javaconfig/security/src/main/java/sample/SessionServlet.java b/samples/javaconfig/security/src/main/java/sample/SessionServlet.java deleted file mode 100644 index 8b78787..0000000 --- a/samples/javaconfig/security/src/main/java/sample/SessionServlet.java +++ /dev/null @@ -1,40 +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("/session") -public class SessionServlet extends HttpServlet { - - @Override - protected void doPost(HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException { - String attributeName = req.getParameter("attributeName"); - String attributeValue = req.getParameter("attributeValue"); - req.getSession().setAttribute(attributeName, attributeValue); - resp.sendRedirect(req.getContextPath() + "/"); - } - - private static final long serialVersionUID = 2878267318695777395L; -} diff --git a/samples/javaconfig/security/src/main/webapp/META-INF/MANIFEST.MF b/samples/javaconfig/security/src/main/webapp/META-INF/MANIFEST.MF deleted file mode 100644 index e69de29..0000000 diff --git a/samples/javaconfig/security/src/main/webapp/index.jsp b/samples/javaconfig/security/src/main/webapp/index.jsp deleted file mode 100644 index 40ecea9..0000000 --- a/samples/javaconfig/security/src/main/webapp/index.jsp +++ /dev/null @@ -1,34 +0,0 @@ -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> -<%@ taglib prefix="wj" uri="http://www.webjars.org/tags" %> - - - - Secured Content - - "> - - - -
-

Description

-

This demonstrates how Spring Session can be combined with Spring Security. The important thing to ensure is that Spring Session's Filter is included before Spring Security's Filter.

- -

Logged in as

- -

You are currently logged in as .

- - -
- - -
-
- - 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 58e24d0..0000000 --- a/samples/javaconfig/users/spring-session-sample-javaconfig-users.gradle +++ /dev/null @@ -1,21 +0,0 @@ -apply plugin: 'io.spring.convention.spring-sample-war' - -dependencies { - compile(project(':spring-session-data-redis')) { - exclude module: 'jedis' - } - compile "org.springframework:spring-web" - compile "io.lettuce:lettuce-core" - compile "org.webjars:bootstrap" - compile "org.webjars:webjars-taglib" - compile jstlDependencies - compile slf4jDependencies - - providedCompile "javax.servlet:javax.servlet-api" - - testCompile "junit:junit" - testCompile "org.springframework:spring-test" - testCompile "org.assertj:assertj-core" - - integrationTestCompile seleniumDependencies -} 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 c3f2ae2..0000000 --- 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 8a6b6b9..0000000 --- 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 a994bdd..0000000 --- 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 1d27240..0000000 --- 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 e09d75f..0000000 --- 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 2356e74..0000000 --- a/samples/javaconfig/users/src/main/java/sample/Config.java +++ /dev/null @@ -1,38 +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 org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; -import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession; - -/** - * @author Rob Winch - */ - -// 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/Initializer.java b/samples/javaconfig/users/src/main/java/sample/Initializer.java deleted file mode 100644 index e1ce969..0000000 --- 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 59e0837..0000000 --- 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 f17ee20..0000000 --- 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 7e49905..0000000 --- a/samples/javaconfig/users/src/main/java/sample/UserAccountsFilter.java +++ /dev/null @@ -1,104 +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 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.getSession(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/webapp/META-INF/MANIFEST.MF b/samples/javaconfig/users/src/main/webapp/META-INF/MANIFEST.MF deleted file mode 100644 index e69de29..0000000 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 b576536..0000000 --- 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 657d2a5..0000000 --- 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 ecf6927..0000000 --- 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/samples/misc/grails3/gradle.properties b/samples/misc/grails3/gradle.properties deleted file mode 100644 index ccd969e..0000000 --- a/samples/misc/grails3/gradle.properties +++ /dev/null @@ -1 +0,0 @@ -grailsVersion=3.1.4 diff --git a/samples/misc/grails3/grails-app/conf/application.groovy b/samples/misc/grails3/grails-app/conf/application.groovy deleted file mode 100644 index 36901ec..0000000 --- a/samples/misc/grails3/grails-app/conf/application.groovy +++ /dev/null @@ -1,28 +0,0 @@ - - -// Added by the Spring Security Core plugin: -grails.plugin.springsecurity.userLookup.userDomainClassName = 'grails3.redis.session.User' -grails.plugin.springsecurity.userLookup.authorityJoinClassName = 'grails3.redis.session.UserRole' -grails.plugin.springsecurity.authority.className = 'grails3.redis.session.Role' -grails.plugin.springsecurity.controllerAnnotations.staticRules = [ - [pattern: '/', access: ['permitAll']], - [pattern: '/error', access: ['permitAll']], - [pattern: '/index', access: ['permitAll']], - [pattern: '/index.gsp', access: ['permitAll']], - [pattern: '/shutdown', access: ['permitAll']], - [pattern: '/assets/**', access: ['permitAll']], - [pattern: '/**/js/**', access: ['permitAll']], - [pattern: '/**/css/**', access: ['permitAll']], - [pattern: '/**/images/**', access: ['permitAll']], - [pattern: '/**/favicon.ico', access: ['permitAll']] -] - -grails.plugin.springsecurity.filterChain.chainMap = [ - [pattern: '/assets/**', filters: 'none'], - [pattern: '/**/js/**', filters: 'none'], - [pattern: '/**/css/**', filters: 'none'], - [pattern: '/**/images/**', filters: 'none'], - [pattern: '/**/favicon.ico', filters: 'none'], - [pattern: '/**', filters: 'JOINED_FILTERS'] -] - diff --git a/samples/misc/grails3/grails-app/conf/application.yml b/samples/misc/grails3/grails-app/conf/application.yml deleted file mode 100644 index 43c77d2..0000000 --- a/samples/misc/grails3/grails-app/conf/application.yml +++ /dev/null @@ -1,122 +0,0 @@ ---- -hibernate: - cache: - queries: false - use_second_level_cache: true - use_query_cache: false - region.factory_class: 'org.hibernate.cache.ehcache.EhCacheRegionFactory' - -dataSource: - pooled: true - jmxExport: true - driverClassName: org.h2.Driver - username: sa - password: - -environments: - development: - dataSource: - dbCreate: create-drop - url: jdbc:h2:mem:devDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE - test: - dataSource: - dbCreate: update - url: jdbc:h2:mem:testDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE - production: - dataSource: - dbCreate: update - url: jdbc:h2:./prodDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE - properties: - jmxEnabled: true - initialSize: 5 - maxActive: 50 - minIdle: 5 - maxIdle: 25 - maxWait: 10000 - maxAge: 600000 - timeBetweenEvictionRunsMillis: 5000 - minEvictableIdleTimeMillis: 60000 - validationQuery: SELECT 1 - validationQueryTimeout: 3 - validationInterval: 15000 - testOnBorrow: true - testWhileIdle: true - testOnReturn: false - jdbcInterceptors: ConnectionState - defaultTransactionIsolation: 2 # TRANSACTION_READ_COMMITTED - ---- ---- -grails: - profile: web - codegen: - defaultPackage: grails3.redis.session - spring: - transactionManagement: - proxies: false -info: - app: - name: '@info.app.name@' - version: '@info.app.version@' - grailsVersion: '@info.app.grailsVersion@' -spring: - - groovy: - template: - check-template-location: false - ---- -grails: - mime: - disable: - accept: - header: - userAgents: - - Gecko - - WebKit - - Presto - - Trident - types: - all: '*/*' - atom: application/atom+xml - css: text/css - csv: text/csv - form: application/x-www-form-urlencoded - html: - - text/html - - application/xhtml+xml - js: text/javascript - json: - - application/json - - text/json - multipartForm: multipart/form-data - pdf: application/pdf - rss: application/rss+xml - text: text/plain - hal: - - application/hal+json - - application/hal+xml - xml: - - text/xml - - application/xml - urlmapping: - cache: - maxsize: 1000 - controllers: - defaultScope: singleton - converters: - encoding: UTF-8 - views: - default: - codec: html - gsp: - encoding: UTF-8 - htmlcodec: xml - codecs: - expression: html - scriptlets: html - taglib: none - staticparts: none -endpoints: - jmx: - unique-names: true diff --git a/samples/misc/grails3/grails-app/conf/logback.groovy b/samples/misc/grails3/grails-app/conf/logback.groovy deleted file mode 100644 index 2f7c41c..0000000 --- a/samples/misc/grails3/grails-app/conf/logback.groovy +++ /dev/null @@ -1,23 +0,0 @@ -import grails.util.BuildSettings -import grails.util.Environment - -// See http://logback.qos.ch/manual/groovy.html for details on configuration -appender('STDOUT', ConsoleAppender) { - encoder(PatternLayoutEncoder) { - pattern = "%level %logger - %msg%n" - } -} - -root(ERROR, ['STDOUT']) - -def targetDir = BuildSettings.TARGET_DIR -if (Environment.isDevelopmentMode() && targetDir) { - appender("FULL_STACKTRACE", FileAppender) { - file = "${targetDir}/stacktrace.log" - append = true - encoder(PatternLayoutEncoder) { - pattern = "%level %logger - %msg%n" - } - } - logger("StackTrace", ERROR, ['FULL_STACKTRACE'], false) -} diff --git a/samples/misc/grails3/grails-app/conf/spring/resources.groovy b/samples/misc/grails3/grails-app/conf/spring/resources.groovy deleted file mode 100644 index fa95006..0000000 --- a/samples/misc/grails3/grails-app/conf/spring/resources.groovy +++ /dev/null @@ -1,3 +0,0 @@ -// Place your Spring DSL code here -beans = { -} diff --git a/samples/misc/grails3/grails-app/controllers/grails3/redis/session/TestController.groovy b/samples/misc/grails3/grails-app/controllers/grails3/redis/session/TestController.groovy deleted file mode 100644 index 60e878d..0000000 --- a/samples/misc/grails3/grails-app/controllers/grails3/redis/session/TestController.groovy +++ /dev/null @@ -1,8 +0,0 @@ -package grails3.redis.session - -import grails.plugin.springsecurity.annotation.Secured - -class TestController { - @Secured('ROLE_ADMIN') - def index() { } // Renders `test/index.gsp` -} diff --git a/samples/misc/grails3/grails-app/controllers/grails3/redis/session/UrlMappings.groovy b/samples/misc/grails3/grails-app/controllers/grails3/redis/session/UrlMappings.groovy deleted file mode 100644 index 436d40d..0000000 --- a/samples/misc/grails3/grails-app/controllers/grails3/redis/session/UrlMappings.groovy +++ /dev/null @@ -1,16 +0,0 @@ -package grails3.redis.session - -class UrlMappings { - - static mappings = { - "/$controller/$action?/$id?(.$format)?"{ - constraints { - // apply constraints here - } - } - - "/"(view:"/index") - "500"(view:'/error') - "404"(view:'/notFound') - } -} diff --git a/samples/misc/grails3/grails-app/domain/grails3/redis/session/Role.groovy b/samples/misc/grails3/grails-app/domain/grails3/redis/session/Role.groovy deleted file mode 100644 index 4705064..0000000 --- a/samples/misc/grails3/grails-app/domain/grails3/redis/session/Role.groovy +++ /dev/null @@ -1,26 +0,0 @@ -package grails3.redis.session - -import groovy.transform.EqualsAndHashCode -import groovy.transform.ToString - -@EqualsAndHashCode(includes='authority') -@ToString(includes='authority', includeNames=true, includePackage=false) -class Role implements Serializable { - - private static final long serialVersionUID = 1 - - String authority - - Role(String authority) { - this() - this.authority = authority - } - - static constraints = { - authority blank: false, unique: true - } - - static mapping = { - cache true - } -} diff --git a/samples/misc/grails3/grails-app/domain/grails3/redis/session/User.groovy b/samples/misc/grails3/grails-app/domain/grails3/redis/session/User.groovy deleted file mode 100644 index 078e249..0000000 --- a/samples/misc/grails3/grails-app/domain/grails3/redis/session/User.groovy +++ /dev/null @@ -1,55 +0,0 @@ -package grails3.redis.session - -import groovy.transform.EqualsAndHashCode -import groovy.transform.ToString - -@EqualsAndHashCode(includes='username') -@ToString(includes='username', includeNames=true, includePackage=false) -class User implements Serializable { - - private static final long serialVersionUID = 1 - - transient springSecurityService - - String username - String password - boolean enabled = true - boolean accountExpired - boolean accountLocked - boolean passwordExpired - - User(String username, String password) { - this() - this.username = username - this.password = password - } - - Set getAuthorities() { - UserRole.findAllByUser(this)*.role - } - - def beforeInsert() { - encodePassword() - } - - def beforeUpdate() { - if (isDirty('password')) { - encodePassword() - } - } - - protected void encodePassword() { - password = springSecurityService?.passwordEncoder ? springSecurityService.encodePassword(password) : password - } - - static transients = ['springSecurityService'] - - static constraints = { - password blank: false, password: true - username blank: false, unique: true - } - - static mapping = { - password column: '`password`' - } -} diff --git a/samples/misc/grails3/grails-app/domain/grails3/redis/session/UserRole.groovy b/samples/misc/grails3/grails-app/domain/grails3/redis/session/UserRole.groovy deleted file mode 100644 index 3ba030f..0000000 --- a/samples/misc/grails3/grails-app/domain/grails3/redis/session/UserRole.groovy +++ /dev/null @@ -1,103 +0,0 @@ -package grails3.redis.session - -import grails.gorm.DetachedCriteria -import groovy.transform.ToString - -import org.apache.commons.lang.builder.HashCodeBuilder - -@ToString(cache=true, includeNames=true, includePackage=false) -class UserRole implements Serializable { - - private static final long serialVersionUID = 1 - - User user - Role role - - UserRole(User u, Role r) { - this() - user = u - role = r - } - - @Override - boolean equals(other) { - if (!(other instanceof UserRole)) { - return false - } - - other.user?.id == user?.id && other.role?.id == role?.id - } - - @Override - int hashCode() { - def builder = new HashCodeBuilder() - if (user) builder.append(user.id) - if (role) builder.append(role.id) - builder.toHashCode() - } - - static UserRole get(long userId, long roleId) { - criteriaFor(userId, roleId).get() - } - - static boolean exists(long userId, long roleId) { - criteriaFor(userId, roleId).count() - } - - private static DetachedCriteria criteriaFor(long userId, long roleId) { - UserRole.where { - user == User.load(userId) && - role == Role.load(roleId) - } - } - - static UserRole create(User user, Role role, boolean flush = false) { - def instance = new UserRole(user: user, role: role) - instance.save(flush: flush, insert: true) - instance - } - - static boolean remove(User u, Role r, boolean flush = false) { - if (u == null || r == null) return false - - int rowCount = UserRole.where { user == u && role == r }.deleteAll() - - if (flush) { UserRole.withSession { it.flush() } } - - rowCount - } - - static void removeAll(User u, boolean flush = false) { - if (u == null) return - - UserRole.where { user == u }.deleteAll() - - if (flush) { UserRole.withSession { it.flush() } } - } - - static void removeAll(Role r, boolean flush = false) { - if (r == null) return - - UserRole.where { role == r }.deleteAll() - - if (flush) { UserRole.withSession { it.flush() } } - } - - static constraints = { - role validator: { Role r, UserRole ur -> - if (ur.user == null || ur.user.id == null) return - boolean existing = false - UserRole.withNewSession { - existing = UserRole.exists(ur.user.id, r.id) - } - if (existing) { - return 'userRole.exists' - } - } - } - - static mapping = { - id composite: ['user', 'role'] - version false - } -} diff --git a/samples/misc/grails3/grails-app/i18n/messages.properties b/samples/misc/grails3/grails-app/i18n/messages.properties deleted file mode 100644 index b045136..0000000 --- a/samples/misc/grails3/grails-app/i18n/messages.properties +++ /dev/null @@ -1,56 +0,0 @@ -default.doesnt.match.message=Property [{0}] of class [{1}] with value [{2}] does not match the required pattern [{3}] -default.invalid.url.message=Property [{0}] of class [{1}] with value [{2}] is not a valid URL -default.invalid.creditCard.message=Property [{0}] of class [{1}] with value [{2}] is not a valid credit card number -default.invalid.email.message=Property [{0}] of class [{1}] with value [{2}] is not a valid e-mail address -default.invalid.range.message=Property [{0}] of class [{1}] with value [{2}] does not fall within the valid range from [{3}] to [{4}] -default.invalid.size.message=Property [{0}] of class [{1}] with value [{2}] does not fall within the valid size range from [{3}] to [{4}] -default.invalid.max.message=Property [{0}] of class [{1}] with value [{2}] exceeds maximum value [{3}] -default.invalid.min.message=Property [{0}] of class [{1}] with value [{2}] is less than minimum value [{3}] -default.invalid.max.size.message=Property [{0}] of class [{1}] with value [{2}] exceeds the maximum size of [{3}] -default.invalid.min.size.message=Property [{0}] of class [{1}] with value [{2}] is less than the minimum size of [{3}] -default.invalid.validator.message=Property [{0}] of class [{1}] with value [{2}] does not pass custom validation -default.not.inlist.message=Property [{0}] of class [{1}] with value [{2}] is not contained within the list [{3}] -default.blank.message=Property [{0}] of class [{1}] cannot be blank -default.not.equal.message=Property [{0}] of class [{1}] with value [{2}] cannot equal [{3}] -default.null.message=Property [{0}] of class [{1}] cannot be null -default.not.unique.message=Property [{0}] of class [{1}] with value [{2}] must be unique - -default.paginate.prev=Previous -default.paginate.next=Next -default.boolean.true=True -default.boolean.false=False -default.date.format=yyyy-MM-dd HH:mm:ss z -default.number.format=0 - -default.created.message={0} {1} created -default.updated.message={0} {1} updated -default.deleted.message={0} {1} deleted -default.not.deleted.message={0} {1} could not be deleted -default.not.found.message={0} not found with id {1} -default.optimistic.locking.failure=Another user has updated this {0} while you were editing - -default.home.label=Home -default.list.label={0} List -default.add.label=Add {0} -default.new.label=New {0} -default.create.label=Create {0} -default.show.label=Show {0} -default.edit.label=Edit {0} - -default.button.create.label=Create -default.button.edit.label=Edit -default.button.update.label=Update -default.button.delete.label=Delete -default.button.delete.confirm.message=Are you sure? - -# Data binding errors. Use "typeMismatch.$className.$propertyName to customize (eg typeMismatch.Book.author) -typeMismatch.java.net.URL=Property {0} must be a valid URL -typeMismatch.java.net.URI=Property {0} must be a valid URI -typeMismatch.java.util.Date=Property {0} must be a valid Date -typeMismatch.java.lang.Double=Property {0} must be a valid number -typeMismatch.java.lang.Integer=Property {0} must be a valid number -typeMismatch.java.lang.Long=Property {0} must be a valid number -typeMismatch.java.lang.Short=Property {0} must be a valid number -typeMismatch.java.math.BigDecimal=Property {0} must be a valid number -typeMismatch.java.math.BigInteger=Property {0} must be a valid number -typeMismatch=Property {0} is type-mismatched diff --git a/samples/misc/grails3/grails-app/init/BootStrap.groovy b/samples/misc/grails3/grails-app/init/BootStrap.groovy deleted file mode 100644 index 1bf1ef4..0000000 --- a/samples/misc/grails3/grails-app/init/BootStrap.groovy +++ /dev/null @@ -1,24 +0,0 @@ -import grails3.redis.session.* - -class BootStrap { - - def init = { servletContext -> - def adminRole = new Role('ROLE_ADMIN').save() - def userRole = new Role('ROLE_USER').save() - - def testUser = new User('user', 'password').save() - - UserRole.create testUser, adminRole - - UserRole.withSession { - it.flush() - it.clear() - } - - assert User.count() == 1 - assert Role.count() == 2 - assert UserRole.count() == 1 - } - def destroy = { - } -} diff --git a/samples/misc/grails3/grails-app/init/grails3/redis/session/Application.groovy b/samples/misc/grails3/grails-app/init/grails3/redis/session/Application.groovy deleted file mode 100644 index b83e7ea..0000000 --- a/samples/misc/grails3/grails-app/init/grails3/redis/session/Application.groovy +++ /dev/null @@ -1,10 +0,0 @@ -package grails3.redis.session - -import grails.boot.GrailsApp -import grails.boot.config.GrailsAutoConfiguration - -class Application extends GrailsAutoConfiguration { - static void main(String[] args) { - GrailsApp.run(Application, args) - } -} \ No newline at end of file diff --git a/samples/misc/grails3/grails-app/views/error.gsp b/samples/misc/grails3/grails-app/views/error.gsp deleted file mode 100644 index 9a3bb8a..0000000 --- a/samples/misc/grails3/grails-app/views/error.gsp +++ /dev/null @@ -1,31 +0,0 @@ - - - - <g:if env="development">Grails Runtime Exception</g:if><g:else>Error</g:else> - - - - - - - - - - - - -
    -
  • An error has occurred
  • -
  • Exception: ${exception}
  • -
  • Message: ${message}
  • -
  • Path: ${path}
  • -
-
-
- -
    -
  • An error has occurred
  • -
-
- - diff --git a/samples/misc/grails3/grails-app/views/index.gsp b/samples/misc/grails3/grails-app/views/index.gsp deleted file mode 100644 index cba0cf9..0000000 --- a/samples/misc/grails3/grails-app/views/index.gsp +++ /dev/null @@ -1,8 +0,0 @@ - - - Index - - - Left blank, goto test - - diff --git a/samples/misc/grails3/grails-app/views/notFound.gsp b/samples/misc/grails3/grails-app/views/notFound.gsp deleted file mode 100644 index 4c873ba..0000000 --- a/samples/misc/grails3/grails-app/views/notFound.gsp +++ /dev/null @@ -1,14 +0,0 @@ - - - - Page Not Found - - - - -
    -
  • Error: Page Not Found (404)
  • -
  • Path: ${request.forwardURI}
  • -
- - diff --git a/samples/misc/grails3/grails-app/views/test/index.gsp b/samples/misc/grails3/grails-app/views/test/index.gsp deleted file mode 100644 index 00b421b..0000000 --- a/samples/misc/grails3/grails-app/views/test/index.gsp +++ /dev/null @@ -1,16 +0,0 @@ - - - Home Page - - -
- -
-
- ${session.id} -
-
- -
- - diff --git a/samples/misc/grails3/spring-session-sample-misc-grails3.gradle b/samples/misc/grails3/spring-session-sample-misc-grails3.gradle deleted file mode 100644 index e57e625..0000000 --- a/samples/misc/grails3/spring-session-sample-misc-grails3.gradle +++ /dev/null @@ -1,71 +0,0 @@ -buildscript { - ext { - grailsVersion = project.grailsVersion - } - repositories { - mavenLocal() - maven { url "https://repo.grails.org/grails/core" } - } - dependencies { - classpath "org.grails:grails-gradle-plugin:$grailsVersion" - classpath "com.bertramlabs.plugins:asset-pipeline-gradle:2.5.0" - classpath "org.grails.plugins:hibernate4:5.0.2" - } -} - -apply plugin: "eclipse" -apply plugin: "idea" -apply plugin: "war" -apply plugin: "org.grails.grails-web" -apply plugin: "org.grails.grails-gsp" -apply plugin: "asset-pipeline" -apply from: SAMPLE_GRADLE - -ext { - grailsVersion = project.grailsVersion -} - -repositories { - mavenLocal() - maven { url "https://repo.grails.org/grails/core" } -} - -dependencyManagement { - imports { - mavenBom "org.grails:grails-bom:$grailsVersion" - } - applyMavenExclusions false -} - -dependencies { - compile "org.springframework.boot:spring-boot-starter-logging" - compile "org.springframework.boot:spring-boot-autoconfigure" - compile "org.grails:grails-core" - compile "org.springframework.boot:spring-boot-starter-actuator" - compile "org.springframework.boot:spring-boot-starter-tomcat" - compile "org.grails:grails-dependencies" - compile "org.grails:grails-web-boot" - compile "org.grails.plugins:cache" - compile "org.grails.plugins:scaffolding" - compile "org.grails.plugins:hibernate4" - compile "org.hibernate:hibernate-ehcache" - console "org.grails:grails-console" - profile "org.grails.profiles:web:3.1.4" - runtime "org.grails.plugins:asset-pipeline" - runtime "com.h2database:h2" - testCompile "org.grails:grails-plugin-testing" - testCompile "org.grails.plugins:geb" - testCompile "org.assertj:assertj-core" - testCompile "org.seleniumhq.selenium:selenium-htmlunit-driver" - testCompile "net.sourceforge.htmlunit:htmlunit" - - compile "org.springframework.boot:spring-boot-starter-redis" - compile 'org.springframework.session:spring-session:1.1.1.RELEASE' - - compile 'org.grails.plugins:spring-security-core:3.0.4' -} - -assets { - minifyJs = true - minifyCss = true -} diff --git a/samples/misc/grails3/src/integration-test/groovy/sample/HomeSpec.groovy b/samples/misc/grails3/src/integration-test/groovy/sample/HomeSpec.groovy deleted file mode 100644 index d96d20c..0000000 --- a/samples/misc/grails3/src/integration-test/groovy/sample/HomeSpec.groovy +++ /dev/null @@ -1,98 +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 grails.test.mixin.integration.Integration -import grails.transaction.Transactional -import org.springframework.boot.test.IntegrationTest - -import spock.lang.* -import geb.spock.* - -import sample.pages.HomePage -import sample.pages.LoginPage -import sample.pages.IndexPage -import spock.lang.Stepwise -import pages.* - -/** - * Functional tests for grails 3 and spring-session - * - * @author Eric Helgeson - */ - -@Stepwise -@IntegrationTest("server.port:0") -@Integration(applicationClass=grails3.redis.session.Application) -class HomeSpec extends GebSpec { - - def setup() { - } - - def cleanup() { - } - - void 'Anonymous page not redirected to login'() { - when: 'The index page is visited' - go '/' - - then: 'Not redirected' - at IndexPage - } - - void 'Unauthenticated user sent to log in page'() { - when: 'The test page is visited' - go '/test/index' - if(title != 'Login') { - println driver.pageSource - } - - then: 'The password form is correct' - title == 'Login' - $('#password') - $('#username') - } - - void 'Log in views home page'() { - when: 'log in successfully' - to LoginPage - login() - - then: 'sent to original page' - at HomePage - - and: 'the username is displayed' - username == 'user' - - and: 'session id is not blank' - session != '' - - and: 'Spring Session Management is being used' - driver.manage().cookies.find { it.name == 'SESSION' } - - and: 'Standard Session is NOT being used' - !driver.manage().cookies.find { it.name == 'JSESSIONID' } - } - - def 'Log out success'() { - when: - logout() - - then: - at IndexPage - } -} diff --git a/samples/misc/grails3/src/integration-test/groovy/sample/pages/HomePage.groovy b/samples/misc/grails3/src/integration-test/groovy/sample/pages/HomePage.groovy deleted file mode 100644 index ae10649..0000000 --- a/samples/misc/grails3/src/integration-test/groovy/sample/pages/HomePage.groovy +++ /dev/null @@ -1,34 +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.pages - -import geb.* - -/** - * The home page - * - * @author Rob Winch - */ -class HomePage extends Page { - static url = '/test' - static at = { assert driver.title == 'Home Page'; true} - static content = { - username { $('#un').text() } - session { $('#session').text() } - logout(to:LoginPage) { $('input[type=submit]').click() } - } -} diff --git a/samples/misc/grails3/src/integration-test/groovy/sample/pages/IndexPage.groovy b/samples/misc/grails3/src/integration-test/groovy/sample/pages/IndexPage.groovy deleted file mode 100644 index 497b90d..0000000 --- a/samples/misc/grails3/src/integration-test/groovy/sample/pages/IndexPage.groovy +++ /dev/null @@ -1,30 +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.pages - -import geb.* - -/** - * The Index page - * - * @author Eric Helgeson - */ -class IndexPage extends Page { - static url = '/' - static at = { assert driver.title == 'Index'; true} - static content = { } -} diff --git a/samples/misc/grails3/src/integration-test/groovy/sample/pages/LoginPage.groovy b/samples/misc/grails3/src/integration-test/groovy/sample/pages/LoginPage.groovy deleted file mode 100644 index 46c7cae..0000000 --- a/samples/misc/grails3/src/integration-test/groovy/sample/pages/LoginPage.groovy +++ /dev/null @@ -1,38 +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.pages - -import geb.* - -/** - * The Login Page - * - * @author Rob Winch - */ -class LoginPage extends Page { - static url = '/login' - static at = { assert driver.title == 'Login'; true} - static content = { - form { $('form') } - submit { $('input[type=submit]') } - login(required:false) { user='user', pass='password' -> - form.username = user - form.password = pass - submit.click() - } - } -} diff --git a/samples/misc/hazelcast/spring-session-sample-misc-hazelcast.gradle b/samples/misc/hazelcast/spring-session-sample-misc-hazelcast.gradle deleted file mode 100644 index 137a5e1..0000000 --- a/samples/misc/hazelcast/spring-session-sample-misc-hazelcast.gradle +++ /dev/null @@ -1,17 +0,0 @@ -apply plugin: 'io.spring.convention.spring-sample-war' - -dependencies { - compile project(':spring-session') - compile "org.webjars:bootstrap" - compile "org.webjars:webjars-taglib" - compile "com.hazelcast:hazelcast-client" - compile jstlDependencies - compile slf4jDependencies - - providedCompile "javax.servlet:javax.servlet-api" - - testCompile "junit:junit" - testCompile "org.assertj:assertj-core" - - integrationTestCompile seleniumDependencies -} diff --git a/samples/misc/hazelcast/src/integration-test/java/sample/AttributeTests.java b/samples/misc/hazelcast/src/integration-test/java/sample/AttributeTests.java deleted file mode 100644 index 587c638..0000000 --- a/samples/misc/hazelcast/src/integration-test/java/sample/AttributeTests.java +++ /dev/null @@ -1,78 +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.util.List; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.openqa.selenium.WebDriver; -import org.openqa.selenium.htmlunit.HtmlUnitDriver; -import sample.pages.HomePage; -import sample.pages.HomePage.Attribute; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Eddú Meléndez - * @author Rob Winch - */ -public class AttributeTests { - - private WebDriver driver; - - @Before - public void setup() { - this.driver = new HtmlUnitDriver(); - } - - @After - public void tearDown() { - this.driver.quit(); - } - - @Test - public void home() { - HomePage home = HomePage.go(this.driver); - home.assertAt(); - } - - @Test - public void noAttributes() { - HomePage home = HomePage.go(this.driver); - assertThat(home.attributes().size()).isEqualTo(0); - } - - @Test - public void createAttribute() { - HomePage home = HomePage.go(this.driver); - // @formatter:off - home = home.form() - .attributeName("a") - .attributeValue("b") - .submit(HomePage.class); - // @formatter:on - - List attributes = home.attributes(); - assertThat(attributes).hasSize(1); - Attribute row = attributes.get(0); - assertThat(row.getAttributeName()).isEqualTo("a"); - assertThat(row.getAttributeValue()).isEqualTo("b"); - } - -} diff --git a/samples/misc/hazelcast/src/integration-test/java/sample/pages/HomePage.java b/samples/misc/hazelcast/src/integration-test/java/sample/pages/HomePage.java deleted file mode 100644 index e9e0134..0000000 --- a/samples/misc/hazelcast/src/integration-test/java/sample/pages/HomePage.java +++ /dev/null @@ -1,135 +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 java.util.ArrayList; -import java.util.List; - -import org.openqa.selenium.SearchContext; -import org.openqa.selenium.WebDriver; -import org.openqa.selenium.WebElement; -import org.openqa.selenium.support.FindBy; -import org.openqa.selenium.support.PageFactory; -import org.openqa.selenium.support.pagefactory.DefaultElementLocatorFactory; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Eddú Meléndez - * @author Rob Winch - */ -public class HomePage { - - private WebDriver driver; - - @FindBy(css = "form") - WebElement form; - - @FindBy(css = "table tbody tr") - List trs; - - List attributes; - - public HomePage(WebDriver driver) { - this.driver = driver; - this.attributes = new ArrayList(); - } - - private static void get(WebDriver driver, String get) { - String baseUrl = "http://localhost:" + System.getProperty("app.port", "8080"); - driver.get(baseUrl + get); - } - - public static HomePage go(WebDriver driver) { - get(driver, "/"); - return PageFactory.initElements(driver, HomePage.class); - } - - public void assertAt() { - assertThat(this.driver.getTitle()).isEqualTo("Session Attributes"); - } - - public List attributes() { - List rows = new ArrayList(); - for (WebElement tr : this.trs) { - rows.add(new Attribute(tr)); - } - this.attributes.addAll(rows); - return this.attributes; - } - - public Form form() { - return new Form(this.form); - } - - public class Form { - @FindBy(name = "attributeName") - WebElement attributeName; - - @FindBy(name = "attributeValue") - WebElement attributeValue; - - @FindBy(css = "input[type=\"submit\"]") - WebElement submit; - - public Form(SearchContext context) { - PageFactory.initElements(new DefaultElementLocatorFactory(context), this); - } - - public Form attributeName(String text) { - this.attributeName.sendKeys(text); - return this; - } - - public Form attributeValue(String text) { - this.attributeValue.sendKeys(text); - return this; - } - - public T submit(Class page) { - this.submit.click(); - return PageFactory.initElements(HomePage.this.driver, page); - } - } - - public static class Attribute { - @FindBy(xpath = ".//td[1]") - WebElement attributeName; - - @FindBy(xpath = ".//td[2]") - WebElement attributeValue; - - public Attribute(SearchContext context) { - PageFactory.initElements(new DefaultElementLocatorFactory(context), this); - } - - /** - * @return the attributeName - */ - public String getAttributeName() { - return this.attributeName.getText(); - } - - /** - * @return the attributeValue - */ - public String getAttributeValue() { - return this.attributeValue.getText(); - } - } - -} diff --git a/samples/misc/hazelcast/src/main/java/sample/Initializer.java b/samples/misc/hazelcast/src/main/java/sample/Initializer.java deleted file mode 100644 index ee0258a..0000000 --- a/samples/misc/hazelcast/src/main/java/sample/Initializer.java +++ /dev/null @@ -1,96 +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 java.net.ServerSocket; -import java.util.EnumSet; -import java.util.Map; - -import javax.servlet.DispatcherType; -import javax.servlet.FilterRegistration.Dynamic; -import javax.servlet.ServletContext; -import javax.servlet.ServletContextEvent; -import javax.servlet.ServletContextListener; -import javax.servlet.annotation.WebListener; - -import com.hazelcast.config.Config; -import com.hazelcast.config.MapConfig; -import com.hazelcast.config.NetworkConfig; -import com.hazelcast.config.SerializerConfig; -import com.hazelcast.core.Hazelcast; -import com.hazelcast.core.HazelcastInstance; - -import org.springframework.session.ExpiringSession; -import org.springframework.session.MapSession; -import org.springframework.session.MapSessionRepository; -import org.springframework.session.SessionRepository; -import org.springframework.session.web.http.SessionRepositoryFilter; - -@WebListener -public class Initializer implements ServletContextListener { - private HazelcastInstance instance; - - public void contextInitialized(ServletContextEvent sce) { - String sessionMapName = "spring:session:sessions"; - ServletContext sc = sce.getServletContext(); - - Config cfg = new Config(); - NetworkConfig netConfig = new NetworkConfig(); - netConfig.setPort(getAvailablePort()); - cfg.setNetworkConfig(netConfig); - SerializerConfig serializer = new SerializerConfig().setTypeClass(Object.class) - .setImplementation(new ObjectStreamSerializer()); - cfg.getSerializationConfig().addSerializerConfig(serializer); - MapConfig mc = new MapConfig(); - mc.setName(sessionMapName); - mc.setTimeToLiveSeconds(MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS); - cfg.addMapConfig(mc); - - this.instance = Hazelcast.newHazelcastInstance(cfg); - Map sessions = this.instance.getMap(sessionMapName); - - SessionRepository sessionRepository = new MapSessionRepository( - sessions); - SessionRepositoryFilter filter = new SessionRepositoryFilter( - sessionRepository); - Dynamic fr = sc.addFilter("springSessionFilter", filter); - fr.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*"); - } - - public void contextDestroyed(ServletContextEvent sce) { - this.instance.shutdown(); - } - - private static int getAvailablePort() { - ServerSocket socket = null; - try { - socket = new ServerSocket(0); - return socket.getLocalPort(); - } - catch (IOException e) { - throw new RuntimeException(e); - } - finally { - try { - socket.close(); - } - catch (IOException e) { - } - } - } -} diff --git a/samples/misc/hazelcast/src/main/java/sample/ObjectStreamSerializer.java b/samples/misc/hazelcast/src/main/java/sample/ObjectStreamSerializer.java deleted file mode 100644 index 1e9149f..0000000 --- a/samples/misc/hazelcast/src/main/java/sample/ObjectStreamSerializer.java +++ /dev/null @@ -1,63 +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 java.io.InputStream; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.OutputStream; - -import com.hazelcast.nio.ObjectDataInput; -import com.hazelcast.nio.ObjectDataOutput; -import com.hazelcast.nio.serialization.StreamSerializer; - -/** - * A {@link StreamSerializer} that uses Java serialization to persist the session. This is - * certainly not the most efficient way to persist sessions, but the example is intended - * to demonstrate using minimal dependencies. For better serialization methods try using - * Kryo. - * - * @author Rob Winch - * - */ -public class ObjectStreamSerializer implements StreamSerializer { - public int getTypeId() { - return 2; - } - - public void write(ObjectDataOutput objectDataOutput, Object object) - throws IOException { - ObjectOutputStream out = new ObjectOutputStream((OutputStream) objectDataOutput); - out.writeObject(object); - out.flush(); - } - - public Object read(ObjectDataInput objectDataInput) throws IOException { - ObjectInputStream in = new ObjectInputStream((InputStream) objectDataInput); - try { - return in.readObject(); - } - catch (ClassNotFoundException e) { - throw new IOException(e); - } - } - - public void destroy() { - } - -} diff --git a/samples/misc/hazelcast/src/main/java/sample/SessionServlet.java b/samples/misc/hazelcast/src/main/java/sample/SessionServlet.java deleted file mode 100644 index 8098f3e..0000000 --- a/samples/misc/hazelcast/src/main/java/sample/SessionServlet.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; - -/** - * @author Rob Winch - */ -@WebServlet("/session") -public class SessionServlet extends HttpServlet { - - @Override - protected void doPost(HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException { - String attributeName = req.getParameter("attributeName"); - String attributeValue = req.getParameter("attributeValue"); - req.getSession().setAttribute(attributeName, attributeValue); - resp.sendRedirect(req.getContextPath() + "/"); - } - - private static final long serialVersionUID = 2878267318695777395L; -} diff --git a/samples/misc/hazelcast/src/main/webapp/META-INF/MANIFEST.MF b/samples/misc/hazelcast/src/main/webapp/META-INF/MANIFEST.MF deleted file mode 100644 index e69de29..0000000 diff --git a/samples/misc/hazelcast/src/main/webapp/index.jsp b/samples/misc/hazelcast/src/main/webapp/index.jsp deleted file mode 100644 index 42b029e..0000000 --- a/samples/misc/hazelcast/src/main/webapp/index.jsp +++ /dev/null @@ -1,50 +0,0 @@ -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> -<%@ taglib prefix="wj" uri="http://www.webjars.org/tags" %> - - - - Session Attributes - - "> - - - -
-

Description

-

This application demonstrates how to use Hazelcast to back your session. Notice that there is no JSESSIONID cookie. We are also able to customize the way of identifying what the requested session id is.

- -

Try it

- -
- - - - - -
- -
- - - - - - - - - - - - - - - - -
Attribute NameAttribute Value
-
- - diff --git a/samples/xml/jdbc/spring-session-sample-xml-jdbc.gradle b/samples/xml/jdbc/spring-session-sample-xml-jdbc.gradle deleted file mode 100644 index c296825..0000000 --- a/samples/xml/jdbc/spring-session-sample-xml-jdbc.gradle +++ /dev/null @@ -1,18 +0,0 @@ -apply plugin: 'io.spring.convention.spring-sample-war' - -dependencies { - compile project(':spring-session-jdbc') - compile "org.springframework:spring-web" - compile "org.webjars:bootstrap" - compile "org.webjars:webjars-taglib" - compile "com.h2database:h2" - compile jstlDependencies - compile slf4jDependencies - - providedCompile "javax.servlet:javax.servlet-api" - - testCompile "junit:junit" - testCompile "org.assertj:assertj-core" - - integrationTestCompile seleniumDependencies -} diff --git a/samples/xml/jdbc/src/integration-test/java/sample/AttributeTests.java b/samples/xml/jdbc/src/integration-test/java/sample/AttributeTests.java deleted file mode 100644 index 97b8342..0000000 --- a/samples/xml/jdbc/src/integration-test/java/sample/AttributeTests.java +++ /dev/null @@ -1,78 +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.util.List; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.openqa.selenium.WebDriver; -import org.openqa.selenium.htmlunit.HtmlUnitDriver; -import sample.pages.HomePage; -import sample.pages.HomePage.Attribute; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Eddú Meléndez - * @author Rob Winch - */ -public class AttributeTests { - - private WebDriver driver; - - @Before - public void setup() { - this.driver = new HtmlUnitDriver(); - } - - @After - public void tearDown() { - this.driver.quit(); - } - - @Test - public void home() { - HomePage home = HomePage.go(this.driver); - home.assertAt(); - } - - @Test - public void noAttributes() { - HomePage home = HomePage.go(this.driver); - assertThat(home.attributes()).isEmpty(); - } - - @Test - public void createAttribute() { - HomePage home = HomePage.go(this.driver); - // @formatter:off - home = home.form() - .attributeName("a") - .attributeValue("b") - .submit(HomePage.class); - // @formatter:on - - List attributes = home.attributes(); - assertThat(attributes).hasSize(1); - Attribute row = attributes.get(0); - assertThat(row.getAttributeName()).isEqualTo("a"); - assertThat(row.getAttributeValue()).isEqualTo("b"); - } - -} diff --git a/samples/xml/jdbc/src/integration-test/java/sample/pages/HomePage.java b/samples/xml/jdbc/src/integration-test/java/sample/pages/HomePage.java deleted file mode 100644 index e9e0134..0000000 --- a/samples/xml/jdbc/src/integration-test/java/sample/pages/HomePage.java +++ /dev/null @@ -1,135 +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 java.util.ArrayList; -import java.util.List; - -import org.openqa.selenium.SearchContext; -import org.openqa.selenium.WebDriver; -import org.openqa.selenium.WebElement; -import org.openqa.selenium.support.FindBy; -import org.openqa.selenium.support.PageFactory; -import org.openqa.selenium.support.pagefactory.DefaultElementLocatorFactory; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Eddú Meléndez - * @author Rob Winch - */ -public class HomePage { - - private WebDriver driver; - - @FindBy(css = "form") - WebElement form; - - @FindBy(css = "table tbody tr") - List trs; - - List attributes; - - public HomePage(WebDriver driver) { - this.driver = driver; - this.attributes = new ArrayList(); - } - - private static void get(WebDriver driver, String get) { - String baseUrl = "http://localhost:" + System.getProperty("app.port", "8080"); - driver.get(baseUrl + get); - } - - public static HomePage go(WebDriver driver) { - get(driver, "/"); - return PageFactory.initElements(driver, HomePage.class); - } - - public void assertAt() { - assertThat(this.driver.getTitle()).isEqualTo("Session Attributes"); - } - - public List attributes() { - List rows = new ArrayList(); - for (WebElement tr : this.trs) { - rows.add(new Attribute(tr)); - } - this.attributes.addAll(rows); - return this.attributes; - } - - public Form form() { - return new Form(this.form); - } - - public class Form { - @FindBy(name = "attributeName") - WebElement attributeName; - - @FindBy(name = "attributeValue") - WebElement attributeValue; - - @FindBy(css = "input[type=\"submit\"]") - WebElement submit; - - public Form(SearchContext context) { - PageFactory.initElements(new DefaultElementLocatorFactory(context), this); - } - - public Form attributeName(String text) { - this.attributeName.sendKeys(text); - return this; - } - - public Form attributeValue(String text) { - this.attributeValue.sendKeys(text); - return this; - } - - public T submit(Class page) { - this.submit.click(); - return PageFactory.initElements(HomePage.this.driver, page); - } - } - - public static class Attribute { - @FindBy(xpath = ".//td[1]") - WebElement attributeName; - - @FindBy(xpath = ".//td[2]") - WebElement attributeValue; - - public Attribute(SearchContext context) { - PageFactory.initElements(new DefaultElementLocatorFactory(context), this); - } - - /** - * @return the attributeName - */ - public String getAttributeName() { - return this.attributeName.getText(); - } - - /** - * @return the attributeValue - */ - public String getAttributeValue() { - return this.attributeValue.getText(); - } - } - -} diff --git a/samples/xml/jdbc/src/main/java/sample/SessionServlet.java b/samples/xml/jdbc/src/main/java/sample/SessionServlet.java deleted file mode 100644 index 43d11d1..0000000 --- a/samples/xml/jdbc/src/main/java/sample/SessionServlet.java +++ /dev/null @@ -1,40 +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.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -// tag::class[] -public class SessionServlet extends HttpServlet { - - @Override - protected void doPost(HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException { - String attributeName = req.getParameter("attributeName"); - String attributeValue = req.getParameter("attributeValue"); - req.getSession().setAttribute(attributeName, attributeValue); - resp.sendRedirect(req.getContextPath() + "/"); - } - - private static final long serialVersionUID = 2878267318695777395L; -} - -// end::class[] diff --git a/samples/xml/jdbc/src/main/webapp/META-INF/MANIFEST.MF b/samples/xml/jdbc/src/main/webapp/META-INF/MANIFEST.MF deleted file mode 100644 index e69de29..0000000 diff --git a/samples/xml/jdbc/src/main/webapp/WEB-INF/spring/session.xml b/samples/xml/jdbc/src/main/webapp/WEB-INF/spring/session.xml deleted file mode 100644 index 35f6d43..0000000 --- a/samples/xml/jdbc/src/main/webapp/WEB-INF/spring/session.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - diff --git a/samples/xml/jdbc/src/main/webapp/WEB-INF/web.xml b/samples/xml/jdbc/src/main/webapp/WEB-INF/web.xml deleted file mode 100644 index 78e6923..0000000 --- a/samples/xml/jdbc/src/main/webapp/WEB-INF/web.xml +++ /dev/null @@ -1,67 +0,0 @@ - - - - - - contextConfigLocation - - /WEB-INF/spring/*.xml - - - - - - - springSessionRepositoryFilter - org.springframework.web.filter.DelegatingFilterProxy - - - springSessionRepositoryFilter - /* - REQUEST - ERROR - - - - - - - - org.springframework.web.context.ContextLoaderListener - - - - - - session - sample.SessionServlet - - - - session - /session - - - - h2Console - org.h2.server.web.WebServlet - - - - h2Console - /h2-console/* - - - - index.jsp - - diff --git a/samples/xml/jdbc/src/main/webapp/index.jsp b/samples/xml/jdbc/src/main/webapp/index.jsp deleted file mode 100644 index 134d930..0000000 --- a/samples/xml/jdbc/src/main/webapp/index.jsp +++ /dev/null @@ -1,50 +0,0 @@ -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> -<%@ taglib prefix="wj" uri="http://www.webjars.org/tags" %> - - - - Session Attributes - - "> - - - -
-

Description

-

This application demonstrates how to use a relational database to back your session. Notice that there is no JSESSIONID cookie. We are also able to customize the way of identifying what the requested session id is.

- -

Try it

- -
- - - - - -
- -
- - - - - - - - - - - - - - - - -
Attribute NameAttribute Value
-
- - diff --git a/samples/xml/redis/spring-session-sample-xml-redis.gradle b/samples/xml/redis/spring-session-sample-xml-redis.gradle deleted file mode 100644 index bc4d612..0000000 --- a/samples/xml/redis/spring-session-sample-xml-redis.gradle +++ /dev/null @@ -1,20 +0,0 @@ -apply plugin: 'io.spring.convention.spring-sample-war' - -dependencies { - compile(project(':spring-session-data-redis')) { - exclude module: 'jedis' - } - compile "org.springframework:spring-web" - compile "io.lettuce:lettuce-core" - compile "org.webjars:bootstrap" - compile "org.webjars:webjars-taglib" - compile jstlDependencies - compile slf4jDependencies - - providedCompile "javax.servlet:javax.servlet-api" - - testCompile "junit:junit" - testCompile "org.assertj:assertj-core" - - integrationTestCompile seleniumDependencies -} diff --git a/samples/xml/redis/src/integration-test/java/sample/AttributeTests.java b/samples/xml/redis/src/integration-test/java/sample/AttributeTests.java deleted file mode 100644 index 1412860..0000000 --- a/samples/xml/redis/src/integration-test/java/sample/AttributeTests.java +++ /dev/null @@ -1,72 +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.util.List; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.openqa.selenium.WebDriver; -import org.openqa.selenium.htmlunit.HtmlUnitDriver; -import sample.pages.HomePage; -import sample.pages.HomePage.Attribute; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Eddú Meléndez - * @author Rob Winch - */ -public class AttributeTests { - - private WebDriver driver; - - @Before - public void setup() { - this.driver = new HtmlUnitDriver(); - } - - @After - public void tearDown() { - this.driver.quit(); - } - - @Test - public void noAttributes() { - HomePage home = HomePage.go(this.driver, HomePage.class); - assertThat(home.attributes()).isEmpty(); - } - - @Test - public void createAttribute() { - HomePage home = HomePage.go(this.driver, HomePage.class); - // @formatter:off - home = home.form() - .attributeName("a") - .attributeValue("b") - .submit(HomePage.class); - // @formatter:on - - List attributes = home.attributes(); - assertThat(attributes).hasSize(1); - Attribute row = attributes.get(0); - assertThat(row.getAttributeName()).isEqualTo("a"); - assertThat(row.getAttributeValue()).isEqualTo("b"); - } - -} diff --git a/samples/xml/redis/src/integration-test/java/sample/pages/HomePage.java b/samples/xml/redis/src/integration-test/java/sample/pages/HomePage.java deleted file mode 100644 index 92b9062..0000000 --- a/samples/xml/redis/src/integration-test/java/sample/pages/HomePage.java +++ /dev/null @@ -1,135 +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 java.util.ArrayList; -import java.util.List; - -import org.openqa.selenium.SearchContext; -import org.openqa.selenium.WebDriver; -import org.openqa.selenium.WebElement; -import org.openqa.selenium.support.FindBy; -import org.openqa.selenium.support.PageFactory; -import org.openqa.selenium.support.pagefactory.DefaultElementLocatorFactory; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Eddú Meléndez - * @author Rob Winch - */ -public class HomePage { - - private WebDriver driver; - - @FindBy(css = "form") - WebElement form; - - @FindBy(css = "table tbody tr") - List trs; - - List attributes; - - public HomePage(WebDriver driver) { - this.driver = driver; - this.attributes = new ArrayList(); - } - - private static void get(WebDriver driver, String get) { - String baseUrl = "http://localhost:" + System.getProperty("app.port", "8080"); - driver.get(baseUrl + get); - } - - public static T go(WebDriver driver, Class page) { - get(driver, "/"); - return PageFactory.initElements(driver, page); - } - - public void assertAt() { - assertThat(this.driver.getTitle()).isEqualTo("Session Attributes"); - } - - public List attributes() { - List rows = new ArrayList(); - for (WebElement tr : this.trs) { - rows.add(new Attribute(tr)); - } - this.attributes.addAll(rows); - return this.attributes; - } - - public Form form() { - return new Form(this.form); - } - - public class Form { - @FindBy(name = "attributeName") - WebElement attributeName; - - @FindBy(name = "attributeValue") - WebElement attributeValue; - - @FindBy(css = "input[type=\"submit\"]") - WebElement submit; - - public Form(SearchContext context) { - PageFactory.initElements(new DefaultElementLocatorFactory(context), this); - } - - public Form attributeName(String text) { - this.attributeName.sendKeys(text); - return this; - } - - public Form attributeValue(String text) { - this.attributeValue.sendKeys(text); - return this; - } - - public T submit(Class page) { - this.submit.click(); - return PageFactory.initElements(HomePage.this.driver, page); - } - } - - public static class Attribute { - @FindBy(xpath = ".//td[1]") - WebElement attributeName; - - @FindBy(xpath = ".//td[2]") - WebElement attributeValue; - - public Attribute(SearchContext context) { - PageFactory.initElements(new DefaultElementLocatorFactory(context), this); - } - - /** - * @return the attributeName - */ - public String getAttributeName() { - return this.attributeName.getText(); - } - - /** - * @return the attributeValue - */ - public String getAttributeValue() { - return this.attributeValue.getText(); - } - } - -} diff --git a/samples/xml/redis/src/main/java/sample/SessionServlet.java b/samples/xml/redis/src/main/java/sample/SessionServlet.java deleted file mode 100644 index 2046605..0000000 --- a/samples/xml/redis/src/main/java/sample/SessionServlet.java +++ /dev/null @@ -1,41 +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.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -// tag::class[] -public class SessionServlet extends HttpServlet { - - @Override - protected void doPost(HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException { - String attributeName = req.getParameter("attributeName"); - String attributeValue = req.getParameter("attributeValue"); - req.getSession().setAttribute(attributeName, attributeValue); - resp.sendRedirect(req.getContextPath() + "/"); - } - - private static final long serialVersionUID = 2878267318695777395L; -} - -// end::class[] diff --git a/samples/xml/redis/src/main/webapp/META-INF/MANIFEST.MF b/samples/xml/redis/src/main/webapp/META-INF/MANIFEST.MF deleted file mode 100644 index e69de29..0000000 diff --git a/samples/xml/redis/src/main/webapp/WEB-INF/spring/session.xml b/samples/xml/redis/src/main/webapp/WEB-INF/spring/session.xml deleted file mode 100644 index 4b56935..0000000 --- a/samples/xml/redis/src/main/webapp/WEB-INF/spring/session.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/samples/xml/redis/src/main/webapp/WEB-INF/web.xml b/samples/xml/redis/src/main/webapp/WEB-INF/web.xml deleted file mode 100644 index fd09adf..0000000 --- a/samples/xml/redis/src/main/webapp/WEB-INF/web.xml +++ /dev/null @@ -1,57 +0,0 @@ - - - - - - contextConfigLocation - - /WEB-INF/spring/*.xml - - - - - - - springSessionRepositoryFilter - org.springframework.web.filter.DelegatingFilterProxy - - - springSessionRepositoryFilter - /* - REQUEST - ERROR - - - - - - - - org.springframework.web.context.ContextLoaderListener - - - - - - session - sample.SessionServlet - - - - session - /session - - - - index.jsp - - diff --git a/samples/xml/redis/src/main/webapp/index.jsp b/samples/xml/redis/src/main/webapp/index.jsp deleted file mode 100644 index d460c12..0000000 --- a/samples/xml/redis/src/main/webapp/index.jsp +++ /dev/null @@ -1,50 +0,0 @@ -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> -<%@ taglib prefix="wj" uri="http://www.webjars.org/tags" %> - - - - Session Attributes - - "> - - - -
-

Description

-

This application demonstrates how to use a Redis instance to back your session. Notice that there is no JSESSIONID cookie. We are also able to customize the way of identifying what the requested session id is.

- -

Try it

- -
- - - - - -
- -
- - - - - - - - - - - - - - - - -
Attribute NameAttribute Value
-
- - diff --git a/settings.gradle b/settings.gradle deleted file mode 100644 index 792dbf0..0000000 --- a/settings.gradle +++ /dev/null @@ -1,27 +0,0 @@ -rootProject.name = 'spring-session-build' - - -FileTree buildFiles = fileTree(rootDir) { - include '**/*.gradle' - exclude '**/gradle', 'settings.gradle', 'buildSrc', '/build.gradle', '.*' - exclude '**/grails3' -} - -String rootDirPath = rootDir.absolutePath + File.separator -buildFiles.each { File buildFile -> - - boolean isDefaultName = 'build.gradle'.equals(buildFile.name) - if(isDefaultName) { - String buildFilePath = buildFile.parentFile.absolutePath - String projectPath = buildFilePath.replace(rootDirPath, '').replaceAll(File.separator, ':') - include projectPath - } else { - String projectName = buildFile.name.replace('.gradle', ''); - String projectPath = ':' + projectName; - include projectPath - def project = findProject("${projectPath}") - project.name = projectName - project.projectDir = buildFile.parentFile - project.buildFileName = buildFile.name - } -} diff --git a/spring-session-data-mongo/spring-session-data-mongo.gradle b/spring-session-data-mongo/spring-session-data-mongo.gradle deleted file mode 100644 index 5989a72..0000000 --- a/spring-session-data-mongo/spring-session-data-mongo.gradle +++ /dev/null @@ -1,8 +0,0 @@ -apply plugin: 'io.spring.convention.spring-pom' - -description = "Aggregator for Spring Session and Spring Data Mongo" - -dependencies { - compile project(':spring-session') - compile "org.springframework.data:spring-data-mongodb" -} diff --git a/spring-session-data-redis/spring-session-data-redis.gradle b/spring-session-data-redis/spring-session-data-redis.gradle deleted file mode 100644 index d02deea..0000000 --- a/spring-session-data-redis/spring-session-data-redis.gradle +++ /dev/null @@ -1,13 +0,0 @@ -apply plugin: 'io.spring.convention.spring-pom' - -description = "Aggregator for Spring Session and Spring Data Redis" - -dependencies { - compile project(':spring-session') - compile ("org.springframework.data:spring-data-redis") { - exclude group: "org.slf4j", module: 'slf4j-api' - exclude group: "org.slf4j", module: 'jcl-over-slf4j' - } - compile "redis.clients:jedis" - compile "org.apache.commons:commons-pool2" -} diff --git a/spring-session-hazelcast/spring-session-hazelcast.gradle b/spring-session-hazelcast/spring-session-hazelcast.gradle deleted file mode 100644 index bb863e0..0000000 --- a/spring-session-hazelcast/spring-session-hazelcast.gradle +++ /dev/null @@ -1,6 +0,0 @@ -apply plugin: 'io.spring.convention.spring-pom' - -dependencies { - compile project(':spring-session') - compile "com.hazelcast:hazelcast" -} \ No newline at end of file diff --git a/spring-session-jdbc/spring-session-jdbc.gradle b/spring-session-jdbc/spring-session-jdbc.gradle deleted file mode 100644 index 58a930b..0000000 --- a/spring-session-jdbc/spring-session-jdbc.gradle +++ /dev/null @@ -1,8 +0,0 @@ -apply plugin: 'io.spring.convention.spring-pom' - -description = "Aggregator for Spring Session and Spring JDBC" - -dependencies { - compile project(':spring-session') - compile "org.springframework:spring-jdbc" -} diff --git a/spring-session/spring-session.gradle b/spring-session/spring-session.gradle deleted file mode 100644 index 9957540..0000000 --- a/spring-session/spring-session.gradle +++ /dev/null @@ -1,36 +0,0 @@ -apply plugin: 'io.spring.convention.spring-module' - -description = "Spring Session" - -dependencies { - compile "commons-logging:commons-logging" - - optional "org.springframework:spring-context" - optional "org.springframework:spring-jdbc" - optional "org.springframework:spring-messaging" - optional "org.springframework:spring-web" - optional "org.springframework:spring-websocket" - optional "org.springframework.data:spring-data-mongodb" - optional "org.springframework.data:spring-data-redis" - optional "org.springframework.security:spring-security-core" - optional "org.springframework.security:spring-security-web" - optional "com.hazelcast:hazelcast" - - provided "javax.servlet:javax.servlet-api" - - integrationTestCompile "redis.clients:jedis" - integrationTestCompile "org.apache.commons:commons-pool2" - integrationTestCompile "org.apache.derby:derby" - integrationTestCompile "com.h2database:h2" - integrationTestCompile "com.hazelcast:hazelcast-client" - integrationTestCompile "org.hsqldb:hsqldb" - integrationTestCompile "de.flapdoodle.embed:de.flapdoodle.embed.mongo" - - - testCompile "junit:junit" - testCompile "org.mockito:mockito-core" - testCompile "edu.umd.cs.mtc:multithreadedtc" - testCompile "org.springframework:spring-test" - testCompile "org.assertj:assertj-core" - testCompile "org.springframework.security:spring-security-core" -} diff --git a/spring-session/src/integration-test/java/org/springframework/session/data/redis/RedisOperationsSessionRepositoryITests.java b/spring-session/src/integration-test/java/org/springframework/session/data/redis/RedisOperationsSessionRepositoryITests.java deleted file mode 100644 index 0b1e24a..0000000 --- a/spring-session/src/integration-test/java/org/springframework/session/data/redis/RedisOperationsSessionRepositoryITests.java +++ /dev/null @@ -1,480 +0,0 @@ -/* - * Copyright 2014-2015 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.data.redis; - -import java.util.Map; -import java.util.UUID; - -import org.junit.Test; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.data.redis.connection.DefaultMessage; -import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; -import org.springframework.data.redis.core.RedisOperations; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.authority.AuthorityUtils; -import org.springframework.security.core.context.SecurityContext; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.session.FindByIndexNameSessionRepository; -import org.springframework.session.Session; -import org.springframework.session.data.AbstractITests; -import org.springframework.session.data.SessionEventRegistry; -import org.springframework.session.data.redis.RedisOperationsSessionRepository.RedisSession; -import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession; -import org.springframework.session.events.SessionCreatedEvent; -import org.springframework.session.events.SessionDestroyedEvent; -import org.springframework.test.context.ContextConfiguration; - -import static org.assertj.core.api.Assertions.assertThat; - -@ContextConfiguration -public class RedisOperationsSessionRepositoryITests extends AbstractITests { - private static final String SPRING_SECURITY_CONTEXT = "SPRING_SECURITY_CONTEXT"; - - private static final String INDEX_NAME = FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME; - - @Autowired - private RedisOperationsSessionRepository repository; - - @Autowired - RedisOperations redis; - - @Test - public void saves() throws InterruptedException { - String username = "saves-" + System.currentTimeMillis(); - - String usernameSessionKey = "spring:session:RedisOperationsSessionRepositoryITests:index:" - + INDEX_NAME + ":" + username; - - RedisSession toSave = this.repository.createSession(); - String expectedAttributeName = "a"; - String expectedAttributeValue = "b"; - toSave.setAttribute(expectedAttributeName, expectedAttributeValue); - Authentication toSaveToken = new UsernamePasswordAuthenticationToken(username, - "password", AuthorityUtils.createAuthorityList("ROLE_USER")); - SecurityContext toSaveContext = SecurityContextHolder.createEmptyContext(); - toSaveContext.setAuthentication(toSaveToken); - toSave.setAttribute(SPRING_SECURITY_CONTEXT, toSaveContext); - toSave.setAttribute(INDEX_NAME, username); - this.registry.clear(); - - this.repository.save(toSave); - - assertThat(this.registry.receivedEvent(toSave.getId())).isTrue(); - assertThat(this.registry.getEvent(toSave.getId())) - .isInstanceOf(SessionCreatedEvent.class); - assertThat(this.redis.boundSetOps(usernameSessionKey).members()) - .contains(toSave.getId()); - - Session session = this.repository.getSession(toSave.getId()); - - assertThat(session.getId()).isEqualTo(toSave.getId()); - assertThat(session.getAttributeNames()).isEqualTo(toSave.getAttributeNames()); - assertThat(session.getAttribute(expectedAttributeName)) - .isEqualTo(toSave.getAttribute(expectedAttributeName)); - - this.registry.clear(); - - this.repository.delete(toSave.getId()); - - assertThat(this.repository.getSession(toSave.getId())).isNull(); - assertThat(this.registry.getEvent(toSave.getId())) - .isInstanceOf(SessionDestroyedEvent.class); - assertThat(this.redis.boundSetOps(usernameSessionKey).members()) - .doesNotContain(toSave.getId()); - - assertThat(this.registry.getEvent(toSave.getId()).getSession() - .getAttribute(expectedAttributeName)).isEqualTo(expectedAttributeValue); - } - - @Test - public void putAllOnSingleAttrDoesNotRemoveOld() { - RedisSession toSave = this.repository.createSession(); - toSave.setAttribute("a", "b"); - - this.repository.save(toSave); - toSave = this.repository.getSession(toSave.getId()); - - toSave.setAttribute("1", "2"); - - this.repository.save(toSave); - toSave = this.repository.getSession(toSave.getId()); - - Session session = this.repository.getSession(toSave.getId()); - assertThat(session.getAttributeNames().size()).isEqualTo(2); - assertThat(session.getAttribute("a")).isEqualTo("b"); - assertThat(session.getAttribute("1")).isEqualTo("2"); - - this.repository.delete(toSave.getId()); - } - - @Test - public void findByPrincipalName() throws Exception { - String principalName = "findByPrincipalName" + UUID.randomUUID(); - RedisSession toSave = this.repository.createSession(); - toSave.setAttribute(INDEX_NAME, principalName); - - this.repository.save(toSave); - - Map findByPrincipalName = this.repository - .findByIndexNameAndIndexValue(INDEX_NAME, principalName); - - assertThat(findByPrincipalName).hasSize(1); - assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId()); - - this.repository.delete(toSave.getId()); - assertThat(this.registry.receivedEvent(toSave.getId())).isTrue(); - - findByPrincipalName = this.repository.findByIndexNameAndIndexValue(INDEX_NAME, - principalName); - - assertThat(findByPrincipalName).hasSize(0); - assertThat(findByPrincipalName.keySet()).doesNotContain(toSave.getId()); - } - - @Test - public void findByPrincipalNameExpireRemovesIndex() throws Exception { - String principalName = "findByPrincipalNameExpireRemovesIndex" - + UUID.randomUUID(); - RedisSession toSave = this.repository.createSession(); - toSave.setAttribute(INDEX_NAME, principalName); - - this.repository.save(toSave); - - String body = "spring:session:RedisOperationsSessionRepositoryITests:sessions:expires:" - + toSave.getId(); - String channel = ":expired"; - DefaultMessage message = new DefaultMessage(channel.getBytes("UTF-8"), - body.getBytes("UTF-8")); - byte[] pattern = new byte[] {}; - this.repository.onMessage(message, pattern); - - Map findByPrincipalName = this.repository - .findByIndexNameAndIndexValue(INDEX_NAME, principalName); - - assertThat(findByPrincipalName).hasSize(0); - assertThat(findByPrincipalName.keySet()).doesNotContain(toSave.getId()); - } - - @Test - public void findByPrincipalNameNoPrincipalNameChange() throws Exception { - String principalName = "findByPrincipalNameNoPrincipalNameChange" - + UUID.randomUUID(); - RedisSession toSave = this.repository.createSession(); - toSave.setAttribute(INDEX_NAME, principalName); - - this.repository.save(toSave); - - toSave.setAttribute("other", "value"); - this.repository.save(toSave); - - Map findByPrincipalName = this.repository - .findByIndexNameAndIndexValue(INDEX_NAME, principalName); - - assertThat(findByPrincipalName).hasSize(1); - assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId()); - } - - @Test - public void findByPrincipalNameNoPrincipalNameChangeReload() throws Exception { - String principalName = "findByPrincipalNameNoPrincipalNameChangeReload" - + UUID.randomUUID(); - RedisSession toSave = this.repository.createSession(); - toSave.setAttribute(INDEX_NAME, principalName); - - this.repository.save(toSave); - - toSave = this.repository.getSession(toSave.getId()); - - toSave.setAttribute("other", "value"); - this.repository.save(toSave); - - Map findByPrincipalName = this.repository - .findByIndexNameAndIndexValue(INDEX_NAME, principalName); - - assertThat(findByPrincipalName).hasSize(1); - assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId()); - } - - @Test - public void findByDeletedPrincipalName() throws Exception { - String principalName = "findByDeletedPrincipalName" + UUID.randomUUID(); - RedisSession toSave = this.repository.createSession(); - toSave.setAttribute(INDEX_NAME, principalName); - - this.repository.save(toSave); - - toSave.setAttribute(INDEX_NAME, null); - this.repository.save(toSave); - - Map findByPrincipalName = this.repository - .findByIndexNameAndIndexValue(INDEX_NAME, principalName); - - assertThat(findByPrincipalName).isEmpty(); - } - - @Test - public void findByChangedPrincipalName() throws Exception { - String principalName = "findByChangedPrincipalName" + UUID.randomUUID(); - String principalNameChanged = "findByChangedPrincipalName" + UUID.randomUUID(); - RedisSession toSave = this.repository.createSession(); - toSave.setAttribute(INDEX_NAME, principalName); - - this.repository.save(toSave); - - toSave.setAttribute(INDEX_NAME, principalNameChanged); - this.repository.save(toSave); - - Map findByPrincipalName = this.repository - .findByIndexNameAndIndexValue(INDEX_NAME, principalName); - assertThat(findByPrincipalName).isEmpty(); - - findByPrincipalName = this.repository.findByIndexNameAndIndexValue(INDEX_NAME, - principalNameChanged); - - assertThat(findByPrincipalName).hasSize(1); - assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId()); - } - - @Test - public void findByDeletedPrincipalNameReload() throws Exception { - String principalName = "findByDeletedPrincipalName" + UUID.randomUUID(); - RedisSession toSave = this.repository.createSession(); - toSave.setAttribute(INDEX_NAME, principalName); - - this.repository.save(toSave); - - RedisSession getSession = this.repository.getSession(toSave.getId()); - getSession.setAttribute(INDEX_NAME, null); - this.repository.save(getSession); - - Map findByPrincipalName = this.repository - .findByIndexNameAndIndexValue(INDEX_NAME, principalName); - - assertThat(findByPrincipalName).isEmpty(); - } - - @Test - public void findByChangedPrincipalNameReload() throws Exception { - String principalName = "findByChangedPrincipalName" + UUID.randomUUID(); - String principalNameChanged = "findByChangedPrincipalName" + UUID.randomUUID(); - RedisSession toSave = this.repository.createSession(); - toSave.setAttribute(INDEX_NAME, principalName); - - this.repository.save(toSave); - - RedisSession getSession = this.repository.getSession(toSave.getId()); - - getSession.setAttribute(INDEX_NAME, principalNameChanged); - this.repository.save(getSession); - - Map findByPrincipalName = this.repository - .findByIndexNameAndIndexValue(INDEX_NAME, principalName); - assertThat(findByPrincipalName).isEmpty(); - - findByPrincipalName = this.repository.findByIndexNameAndIndexValue(INDEX_NAME, - principalNameChanged); - - assertThat(findByPrincipalName).hasSize(1); - assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId()); - } - - @Test - public void findBySecurityPrincipalName() throws Exception { - RedisSession toSave = this.repository.createSession(); - toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.context); - - this.repository.save(toSave); - - Map findByPrincipalName = this.repository - .findByIndexNameAndIndexValue(INDEX_NAME, getSecurityName()); - - assertThat(findByPrincipalName).hasSize(1); - assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId()); - - this.repository.delete(toSave.getId()); - assertThat(this.registry.receivedEvent(toSave.getId())).isTrue(); - - findByPrincipalName = this.repository.findByIndexNameAndIndexValue(INDEX_NAME, - getSecurityName()); - - assertThat(findByPrincipalName).hasSize(0); - assertThat(findByPrincipalName.keySet()).doesNotContain(toSave.getId()); - } - - @Test - public void findBySecurityPrincipalNameExpireRemovesIndex() throws Exception { - RedisSession toSave = this.repository.createSession(); - toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.context); - - this.repository.save(toSave); - - String body = "spring:session:RedisOperationsSessionRepositoryITests:sessions:expires:" - + toSave.getId(); - String channel = ":expired"; - DefaultMessage message = new DefaultMessage(channel.getBytes("UTF-8"), - body.getBytes("UTF-8")); - byte[] pattern = new byte[] {}; - this.repository.onMessage(message, pattern); - - Map findByPrincipalName = this.repository - .findByIndexNameAndIndexValue(INDEX_NAME, getSecurityName()); - - assertThat(findByPrincipalName).hasSize(0); - assertThat(findByPrincipalName.keySet()).doesNotContain(toSave.getId()); - } - - @Test - public void findByPrincipalNameNoSecurityPrincipalNameChange() throws Exception { - RedisSession toSave = this.repository.createSession(); - toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.context); - - this.repository.save(toSave); - - toSave.setAttribute("other", "value"); - this.repository.save(toSave); - - Map findByPrincipalName = this.repository - .findByIndexNameAndIndexValue(INDEX_NAME, getSecurityName()); - - assertThat(findByPrincipalName).hasSize(1); - assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId()); - } - - @Test - public void findByPrincipalNameNoSecurityPrincipalNameChangeReload() - throws Exception { - RedisSession toSave = this.repository.createSession(); - toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.context); - - this.repository.save(toSave); - - toSave = this.repository.getSession(toSave.getId()); - - toSave.setAttribute("other", "value"); - this.repository.save(toSave); - - Map findByPrincipalName = this.repository - .findByIndexNameAndIndexValue(INDEX_NAME, getSecurityName()); - - assertThat(findByPrincipalName).hasSize(1); - assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId()); - } - - @Test - public void findByDeletedSecurityPrincipalName() throws Exception { - RedisSession toSave = this.repository.createSession(); - toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.context); - - this.repository.save(toSave); - - toSave.setAttribute(SPRING_SECURITY_CONTEXT, null); - this.repository.save(toSave); - - Map findByPrincipalName = this.repository - .findByIndexNameAndIndexValue(INDEX_NAME, getSecurityName()); - - assertThat(findByPrincipalName).isEmpty(); - } - - @Test - public void findByChangedSecurityPrincipalName() throws Exception { - RedisSession toSave = this.repository.createSession(); - toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.context); - - this.repository.save(toSave); - - toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.changedContext); - this.repository.save(toSave); - - Map findByPrincipalName = this.repository - .findByIndexNameAndIndexValue(INDEX_NAME, getSecurityName()); - assertThat(findByPrincipalName).isEmpty(); - - findByPrincipalName = this.repository.findByIndexNameAndIndexValue(INDEX_NAME, - getChangedSecurityName()); - - assertThat(findByPrincipalName).hasSize(1); - assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId()); - } - - @Test - public void findByDeletedSecurityPrincipalNameReload() throws Exception { - RedisSession toSave = this.repository.createSession(); - toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.context); - - this.repository.save(toSave); - - RedisSession getSession = this.repository.getSession(toSave.getId()); - getSession.setAttribute(INDEX_NAME, null); - this.repository.save(getSession); - - Map findByPrincipalName = this.repository - .findByIndexNameAndIndexValue(INDEX_NAME, getChangedSecurityName()); - - assertThat(findByPrincipalName).isEmpty(); - } - - @Test - public void findByChangedSecurityPrincipalNameReload() throws Exception { - RedisSession toSave = this.repository.createSession(); - toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.context); - - this.repository.save(toSave); - - RedisSession getSession = this.repository.getSession(toSave.getId()); - - getSession.setAttribute(SPRING_SECURITY_CONTEXT, this.changedContext); - this.repository.save(getSession); - - Map findByPrincipalName = this.repository - .findByIndexNameAndIndexValue(INDEX_NAME, getSecurityName()); - assertThat(findByPrincipalName).isEmpty(); - - findByPrincipalName = this.repository.findByIndexNameAndIndexValue(INDEX_NAME, - getChangedSecurityName()); - - assertThat(findByPrincipalName).hasSize(1); - assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId()); - } - - private String getSecurityName() { - return this.context.getAuthentication().getName(); - } - - private String getChangedSecurityName() { - return this.changedContext.getAuthentication().getName(); - } - - @Configuration - @EnableRedisHttpSession(redisNamespace = "RedisOperationsSessionRepositoryITests") - static class Config { - @Bean - public JedisConnectionFactory connectionFactory() throws Exception { - JedisConnectionFactory factory = new JedisConnectionFactory(); - factory.setUsePool(false); - return factory; - } - - @Bean - public SessionEventRegistry sessionEventRegistry() { - return new SessionEventRegistry(); - } - } -} diff --git a/spring-session/src/integration-test/java/org/springframework/session/data/redis/config/annotation/web/http/EnableRedisHttpSessionExpireSessionDestroyedTests.java b/spring-session/src/integration-test/java/org/springframework/session/data/redis/config/annotation/web/http/EnableRedisHttpSessionExpireSessionDestroyedTests.java deleted file mode 100644 index 2c14037..0000000 --- a/spring-session/src/integration-test/java/org/springframework/session/data/redis/config/annotation/web/http/EnableRedisHttpSessionExpireSessionDestroyedTests.java +++ /dev/null @@ -1,126 +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.data.redis.config.annotation.web.http; - -import java.util.concurrent.TimeUnit; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationListener; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.authority.AuthorityUtils; -import org.springframework.security.core.context.SecurityContext; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.session.ExpiringSession; -import org.springframework.session.SessionRepository; -import org.springframework.session.events.SessionExpiredEvent; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.springframework.test.context.web.WebAppConfiguration; - -import static org.assertj.core.api.Assertions.assertThat; - -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration -@WebAppConfiguration -public class EnableRedisHttpSessionExpireSessionDestroyedTests { - @Autowired - private SessionRepository repository; - - @Autowired - private SessionExpiredEventRegistry registry; - - private final Object lock = new Object(); - - @Before - public void setup() { - this.registry.setLock(this.lock); - } - - @Test - public void expireFiresSessionExpiredEvent() throws InterruptedException { - S toSave = this.repository.createSession(); - toSave.setAttribute("a", "b"); - Authentication toSaveToken = new UsernamePasswordAuthenticationToken("user", - "password", AuthorityUtils.createAuthorityList("ROLE_USER")); - SecurityContext toSaveContext = SecurityContextHolder.createEmptyContext(); - toSaveContext.setAuthentication(toSaveToken); - toSave.setAttribute("SPRING_SECURITY_CONTEXT", toSaveContext); - - this.repository.save(toSave); - - synchronized (this.lock) { - this.lock.wait((toSave.getMaxInactiveIntervalInSeconds() * 1000) + 1); - } - if (!this.registry.receivedEvent()) { - // Redis makes no guarantees on when an expired event will be fired - // we can ensure it gets fired by trying to get the session - this.repository.getSession(toSave.getId()); - synchronized (this.lock) { - if (!this.registry.receivedEvent()) { - // wait at most a minute - this.lock.wait(TimeUnit.MINUTES.toMillis(1)); - } - } - } - assertThat(this.registry.receivedEvent()).isTrue(); - } - - static class SessionExpiredEventRegistry - implements ApplicationListener { - private boolean receivedEvent; - private Object lock; - - public void onApplicationEvent(SessionExpiredEvent event) { - synchronized (this.lock) { - this.receivedEvent = true; - this.lock.notifyAll(); - } - } - - public boolean receivedEvent() { - return this.receivedEvent; - } - - public void setLock(Object lock) { - this.lock = lock; - } - } - - @Configuration - @EnableRedisHttpSession(maxInactiveIntervalInSeconds = 1) - static class Config { - @Bean - public JedisConnectionFactory connectionFactory() throws Exception { - JedisConnectionFactory factory = new JedisConnectionFactory(); - factory.setUsePool(false); - return factory; - } - - @Bean - public SessionExpiredEventRegistry sessionDestroyedEventRegistry() { - return new SessionExpiredEventRegistry(); - } - } -} diff --git a/spring-session/src/integration-test/java/org/springframework/session/data/redis/flushimmediately/RedisHttpSessionConfig.java b/spring-session/src/integration-test/java/org/springframework/session/data/redis/flushimmediately/RedisHttpSessionConfig.java deleted file mode 100644 index 9765b8b..0000000 --- a/spring-session/src/integration-test/java/org/springframework/session/data/redis/flushimmediately/RedisHttpSessionConfig.java +++ /dev/null @@ -1,38 +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.data.redis.flushimmediately; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; -import org.springframework.session.data.redis.RedisFlushMode; -import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession; - -/** - * @author Rob Winch - * - */ -@Configuration -@EnableRedisHttpSession(redisFlushMode = RedisFlushMode.IMMEDIATE) -public class RedisHttpSessionConfig { - @Bean - public JedisConnectionFactory connectionFactory() throws Exception { - JedisConnectionFactory factory = new JedisConnectionFactory(); - factory.setUsePool(false); - return factory; - } -} diff --git a/spring-session/src/integration-test/java/org/springframework/session/data/redis/flushimmediately/RedisOperationsSessionRepositoryFlushImmediatelyITests.java b/spring-session/src/integration-test/java/org/springframework/session/data/redis/flushimmediately/RedisOperationsSessionRepositoryFlushImmediatelyITests.java deleted file mode 100644 index 5cd7705..0000000 --- a/spring-session/src/integration-test/java/org/springframework/session/data/redis/flushimmediately/RedisOperationsSessionRepositoryFlushImmediatelyITests.java +++ /dev/null @@ -1,47 +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.data.redis.flushimmediately; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.session.ExpiringSession; -import org.springframework.session.SessionRepository; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.springframework.test.context.web.WebAppConfiguration; - -import static org.assertj.core.api.Assertions.assertThat; - -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(classes = RedisHttpSessionConfig.class) -@WebAppConfiguration -public class RedisOperationsSessionRepositoryFlushImmediatelyITests { - - @Autowired - private SessionRepository sessionRepository; - - @Test - public void savesOnCreate() throws InterruptedException { - S created = this.sessionRepository.createSession(); - - S getSession = this.sessionRepository.getSession(created.getId()); - - assertThat(getSession).isNotNull(); - } -} diff --git a/spring-session/src/integration-test/java/org/springframework/session/data/redis/taskexecutor/RedisListenerContainerTaskExecutorITests.java b/spring-session/src/integration-test/java/org/springframework/session/data/redis/taskexecutor/RedisListenerContainerTaskExecutorITests.java deleted file mode 100644 index 3244f84..0000000 --- a/spring-session/src/integration-test/java/org/springframework/session/data/redis/taskexecutor/RedisListenerContainerTaskExecutorITests.java +++ /dev/null @@ -1,121 +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.data.redis.taskexecutor; - -import java.util.concurrent.Executor; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; - -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.core.task.SimpleAsyncTaskExecutor; -import org.springframework.core.task.TaskExecutor; -import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; -import org.springframework.data.redis.core.BoundSetOperations; -import org.springframework.data.redis.core.RedisOperations; -import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.springframework.test.context.web.WebAppConfiguration; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Vladimir Tsanev - */ -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration -@WebAppConfiguration -public class RedisListenerContainerTaskExecutorITests { - - @Autowired - SessionTaskExecutor executor; - - @Autowired - RedisOperations redis; - - @Test - public void testRedisDelEventsAreDispatchedInSessionTaskExecutor() - throws InterruptedException { - BoundSetOperations ops = this.redis.boundSetOps( - "spring:session:RedisListenerContainerTaskExecutorITests:expirations:dummy"); - ops.add("value"); - ops.remove("value"); - assertThat(this.executor.taskDispatched()).isTrue(); - - } - - static class SessionTaskExecutor implements TaskExecutor { - private Object lock = new Object(); - - private final Executor executor; - - private Boolean taskDispatched; - - SessionTaskExecutor(Executor executor) { - this.executor = executor; - } - - public void execute(Runnable task) { - synchronized (this.lock) { - try { - this.executor.execute(task); - } - finally { - this.taskDispatched = true; - this.lock.notifyAll(); - } - } - } - - public boolean taskDispatched() throws InterruptedException { - if (this.taskDispatched != null) { - return this.taskDispatched; - } - synchronized (this.lock) { - this.lock.wait(TimeUnit.SECONDS.toMillis(1)); - } - return this.taskDispatched == null ? Boolean.FALSE : this.taskDispatched; - } - } - - @Configuration - @EnableRedisHttpSession(redisNamespace = "RedisListenerContainerTaskExecutorITests") - static class Config { - - @Bean - JedisConnectionFactory connectionFactory() throws Exception { - JedisConnectionFactory factory = new JedisConnectionFactory(); - factory.setUsePool(false); - return factory; - } - - @Bean - Executor springSessionRedisTaskExecutor() { - return new SessionTaskExecutor(Executors.newSingleThreadExecutor()); - } - - @Bean - Executor springSessionRedisSubscriptionExecutor() { - return new SimpleAsyncTaskExecutor(); - } - } -} diff --git a/spring-session/src/integration-test/java/org/springframework/session/hazelcast/AbstractHazelcastRepositoryITests.java b/spring-session/src/integration-test/java/org/springframework/session/hazelcast/AbstractHazelcastRepositoryITests.java deleted file mode 100644 index 9cd1fea..0000000 --- a/spring-session/src/integration-test/java/org/springframework/session/hazelcast/AbstractHazelcastRepositoryITests.java +++ /dev/null @@ -1,63 +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.hazelcast; - -import com.hazelcast.core.HazelcastInstance; -import com.hazelcast.core.IMap; -import org.junit.Test; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.session.MapSession; -import org.springframework.session.hazelcast.HazelcastSessionRepository.HazelcastSession; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Abstract base class for Hazelcast integration tests. - * - * @author Tommy Ludwig - * @author Vedran Pavic - */ -public abstract class AbstractHazelcastRepositoryITests { - - @Autowired - private HazelcastInstance hazelcast; - - @Autowired - private HazelcastSessionRepository repository; - - @Test - public void createAndDestroySession() { - HazelcastSession sessionToSave = this.repository.createSession(); - String sessionId = sessionToSave.getId(); - - IMap hazelcastMap = this.hazelcast.getMap( - "spring:session:sessions"); - - assertThat(hazelcastMap.size()).isEqualTo(0); - - this.repository.save(sessionToSave); - - assertThat(hazelcastMap.size()).isEqualTo(1); - assertThat(hazelcastMap.get(sessionId)).isEqualTo(sessionToSave); - - this.repository.delete(sessionId); - - assertThat(hazelcastMap.size()).isEqualTo(0); - } - -} diff --git a/spring-session/src/integration-test/java/org/springframework/session/hazelcast/HazelcastClientRepositoryITests.java b/spring-session/src/integration-test/java/org/springframework/session/hazelcast/HazelcastClientRepositoryITests.java deleted file mode 100644 index 7dab018..0000000 --- a/spring-session/src/integration-test/java/org/springframework/session/hazelcast/HazelcastClientRepositoryITests.java +++ /dev/null @@ -1,76 +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.hazelcast; - -import com.hazelcast.client.HazelcastClient; -import com.hazelcast.client.config.ClientConfig; -import com.hazelcast.core.HazelcastInstance; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.runner.RunWith; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.session.hazelcast.config.annotation.web.http.EnableHazelcastHttpSession; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.springframework.test.context.web.WebAppConfiguration; -import org.springframework.util.SocketUtils; - -/** - * Integration tests that check the underlying data source - in this case Hazelcast - * Client. - * - * @author Vedran Pavic - * @author Artem Bilan - * @since 1.1 - */ -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration -@WebAppConfiguration -public class HazelcastClientRepositoryITests extends AbstractHazelcastRepositoryITests { - - private static final int PORT = SocketUtils.findAvailableTcpPort(); - - private static HazelcastInstance hazelcastInstance; - - @BeforeClass - public static void setup() { - hazelcastInstance = HazelcastITestUtils.embeddedHazelcastServer(PORT); - } - - @AfterClass - public static void teardown() { - if (hazelcastInstance != null) { - hazelcastInstance.shutdown(); - } - } - - @Configuration - @EnableHazelcastHttpSession - static class HazelcastSessionConfig { - - @Bean - public HazelcastInstance embeddedHazelcastClient() { - ClientConfig clientConfig = new ClientConfig(); - clientConfig.getNetworkConfig().addAddress("127.0.0.1:" + PORT); - return HazelcastClient.newHazelcastClient(clientConfig); - } - - } - -} diff --git a/spring-session/src/integration-test/java/org/springframework/session/hazelcast/HazelcastITestUtils.java b/spring-session/src/integration-test/java/org/springframework/session/hazelcast/HazelcastITestUtils.java deleted file mode 100644 index 119232c..0000000 --- a/spring-session/src/integration-test/java/org/springframework/session/hazelcast/HazelcastITestUtils.java +++ /dev/null @@ -1,68 +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.hazelcast; - -import com.hazelcast.config.Config; -import com.hazelcast.config.MapAttributeConfig; -import com.hazelcast.config.MapIndexConfig; -import com.hazelcast.core.Hazelcast; -import com.hazelcast.core.HazelcastInstance; - -import org.springframework.util.SocketUtils; - -/** - * Utility class for Hazelcast integration tests. - * - * @author Vedran Pavic - */ -public final class HazelcastITestUtils { - - private HazelcastITestUtils() { - } - - /** - * Creates {@link HazelcastInstance} for use in integration tests. - * @param port the port for Hazelcast to bind to - * @return the Hazelcast instance - */ - public static HazelcastInstance embeddedHazelcastServer(int port) { - MapAttributeConfig attributeConfig = new MapAttributeConfig() - .setName(HazelcastSessionRepository.PRINCIPAL_NAME_ATTRIBUTE) - .setExtractor(PrincipalNameExtractor.class.getName()); - - Config config = new Config(); - - config.getNetworkConfig() - .setPort(port); - - config.getMapConfig("spring:session:sessions") - .addMapAttributeConfig(attributeConfig) - .addMapIndexConfig(new MapIndexConfig( - HazelcastSessionRepository.PRINCIPAL_NAME_ATTRIBUTE, false)); - - return Hazelcast.newHazelcastInstance(config); - } - - /** - * Creates {@link HazelcastInstance} for use in integration tests. - * @return the Hazelcast instance - */ - public static HazelcastInstance embeddedHazelcastServer() { - return embeddedHazelcastServer(SocketUtils.findAvailableTcpPort()); - } - -} diff --git a/spring-session/src/integration-test/java/org/springframework/session/hazelcast/HazelcastServerRepositoryITests.java b/spring-session/src/integration-test/java/org/springframework/session/hazelcast/HazelcastServerRepositoryITests.java deleted file mode 100644 index 3749f89..0000000 --- a/spring-session/src/integration-test/java/org/springframework/session/hazelcast/HazelcastServerRepositoryITests.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.hazelcast; - -import com.hazelcast.core.HazelcastInstance; -import org.junit.runner.RunWith; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.session.hazelcast.config.annotation.web.http.EnableHazelcastHttpSession; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.springframework.test.context.web.WebAppConfiguration; - -/** - * Integration tests that check the underlying data source - in this case Hazelcast - * Server. - * - * @author Tommy Ludwig - * @author Vedran Pavic - */ -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration -@WebAppConfiguration -public class HazelcastServerRepositoryITests extends AbstractHazelcastRepositoryITests { - - @EnableHazelcastHttpSession - @Configuration - static class HazelcastSessionConfig { - - @Bean - public HazelcastInstance embeddedHazelcastServer() { - return HazelcastITestUtils.embeddedHazelcastServer(); - } - - } - -} diff --git a/spring-session/src/integration-test/java/org/springframework/session/hazelcast/config/annotation/web/http/EnableHazelcastHttpSessionEventsTests.java b/spring-session/src/integration-test/java/org/springframework/session/hazelcast/config/annotation/web/http/EnableHazelcastHttpSessionEventsTests.java deleted file mode 100644 index d42e43b..0000000 --- a/spring-session/src/integration-test/java/org/springframework/session/hazelcast/config/annotation/web/http/EnableHazelcastHttpSessionEventsTests.java +++ /dev/null @@ -1,184 +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.hazelcast.config.annotation.web.http; - -import com.hazelcast.core.HazelcastInstance; -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.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.authority.AuthorityUtils; -import org.springframework.security.core.context.SecurityContext; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.session.ExpiringSession; -import org.springframework.session.FindByIndexNameSessionRepository; -import org.springframework.session.Session; -import org.springframework.session.SessionRepository; -import org.springframework.session.data.SessionEventRegistry; -import org.springframework.session.events.SessionCreatedEvent; -import org.springframework.session.events.SessionDeletedEvent; -import org.springframework.session.events.SessionExpiredEvent; -import org.springframework.session.hazelcast.HazelcastITestUtils; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.springframework.test.context.web.WebAppConfiguration; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Ensure that the appropriate SessionEvents are fired at the expected times. Additionally - * ensure that the interactions with the {@link SessionRepository} abstraction behave as - * expected after each SessionEvent. - * - * @author Tommy Ludwig - */ -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration -@WebAppConfiguration -public class EnableHazelcastHttpSessionEventsTests { - - private final static int MAX_INACTIVE_INTERVAL_IN_SECONDS = 1; - - @Autowired - private SessionRepository repository; - - @Autowired - private SessionEventRegistry registry; - - @Before - public void setup() { - this.registry.clear(); - } - - @Test - public void saveSessionTest() throws InterruptedException { - String username = "saves-" + System.currentTimeMillis(); - - S sessionToSave = this.repository.createSession(); - - String expectedAttributeName = "a"; - String expectedAttributeValue = "b"; - sessionToSave.setAttribute(expectedAttributeName, expectedAttributeValue); - Authentication toSaveToken = new UsernamePasswordAuthenticationToken(username, - "password", AuthorityUtils.createAuthorityList("ROLE_USER")); - SecurityContext toSaveContext = SecurityContextHolder.createEmptyContext(); - toSaveContext.setAuthentication(toSaveToken); - sessionToSave.setAttribute("SPRING_SECURITY_CONTEXT", toSaveContext); - sessionToSave.setAttribute( - FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, username); - - this.repository.save(sessionToSave); - - assertThat(this.registry.receivedEvent(sessionToSave.getId())).isTrue(); - assertThat(this.registry.getEvent(sessionToSave.getId())) - .isInstanceOf(SessionCreatedEvent.class); - - Session session = this.repository.getSession(sessionToSave.getId()); - - assertThat(session.getId()).isEqualTo(sessionToSave.getId()); - assertThat(session.getAttributeNames()) - .isEqualTo(sessionToSave.getAttributeNames()); - assertThat(session.getAttribute(expectedAttributeName)) - .isEqualTo(sessionToSave.getAttribute(expectedAttributeName)); - } - - @Test - public void expiredSessionTest() throws InterruptedException { - S sessionToSave = this.repository.createSession(); - - this.repository.save(sessionToSave); - - assertThat(this.registry.receivedEvent(sessionToSave.getId())).isTrue(); - assertThat(this.registry.getEvent(sessionToSave.getId())) - .isInstanceOf(SessionCreatedEvent.class); - this.registry.clear(); - - assertThat(sessionToSave.getMaxInactiveIntervalInSeconds()) - .isEqualTo(MAX_INACTIVE_INTERVAL_IN_SECONDS); - - assertThat(this.registry.receivedEvent(sessionToSave.getId())).isTrue(); - assertThat(this.registry.getEvent(sessionToSave.getId())) - .isInstanceOf(SessionExpiredEvent.class); - - assertThat(this.repository.getSession(sessionToSave.getId())).isNull(); - } - - @Test - public void deletedSessionTest() throws InterruptedException { - S sessionToSave = this.repository.createSession(); - - this.repository.save(sessionToSave); - - assertThat(this.registry.receivedEvent(sessionToSave.getId())).isTrue(); - assertThat(this.registry.getEvent(sessionToSave.getId())) - .isInstanceOf(SessionCreatedEvent.class); - this.registry.clear(); - - this.repository.delete(sessionToSave.getId()); - - assertThat(this.registry.receivedEvent(sessionToSave.getId())).isTrue(); - assertThat(this.registry.getEvent(sessionToSave.getId())) - .isInstanceOf(SessionDeletedEvent.class); - - assertThat(this.repository.getSession(sessionToSave.getId())).isNull(); - } - - @Test - public void saveUpdatesTimeToLiveTest() throws InterruptedException { - Object lock = new Object(); - - S sessionToSave = this.repository.createSession(); - - this.repository.save(sessionToSave); - - synchronized (lock) { - lock.wait((sessionToSave.getMaxInactiveIntervalInSeconds() * 1000) - 500); - } - - // Get and save the session like SessionRepositoryFilter would. - S sessionToUpdate = this.repository.getSession(sessionToSave.getId()); - sessionToUpdate.setLastAccessedTime(System.currentTimeMillis()); - this.repository.save(sessionToUpdate); - - synchronized (lock) { - lock.wait((sessionToUpdate.getMaxInactiveIntervalInSeconds() * 1000) - 100); - } - - assertThat(this.repository.getSession(sessionToUpdate.getId())).isNotNull(); - } - - @Configuration - @EnableHazelcastHttpSession(maxInactiveIntervalInSeconds = MAX_INACTIVE_INTERVAL_IN_SECONDS) - static class HazelcastSessionConfig { - - @Bean - public HazelcastInstance embeddedHazelcast() { - return HazelcastITestUtils.embeddedHazelcastServer(); - } - - @Bean - public SessionEventRegistry sessionEventRegistry() { - return new SessionEventRegistry(); - } - } - -} diff --git a/spring-session/src/integration-test/java/org/springframework/session/hazelcast/config/annotation/web/http/HazelcastHttpSessionConfigurationXmlTests.java b/spring-session/src/integration-test/java/org/springframework/session/hazelcast/config/annotation/web/http/HazelcastHttpSessionConfigurationXmlTests.java deleted file mode 100644 index e128b30..0000000 --- a/spring-session/src/integration-test/java/org/springframework/session/hazelcast/config/annotation/web/http/HazelcastHttpSessionConfigurationXmlTests.java +++ /dev/null @@ -1,121 +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.hazelcast.config.annotation.web.http; - -import com.hazelcast.config.ClasspathXmlConfig; -import com.hazelcast.config.Config; -import com.hazelcast.config.NetworkConfig; -import com.hazelcast.core.Hazelcast; -import com.hazelcast.core.HazelcastInstance; -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.session.ExpiringSession; -import org.springframework.session.SessionRepository; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.springframework.test.context.web.WebAppConfiguration; -import org.springframework.util.SocketUtils; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Test the different configuration options for the {@link EnableHazelcastHttpSession} - * annotation. - * - * @author Tommy Ludwig - */ -public class HazelcastHttpSessionConfigurationXmlTests { - - @RunWith(SpringJUnit4ClassRunner.class) - @ContextConfiguration - @WebAppConfiguration - public static class CustomXmlMapNameTest { - - @Autowired - private SessionRepository repository; - - @Test - public void saveSessionTest() throws InterruptedException { - - S sessionToSave = this.repository.createSession(); - - this.repository.save(sessionToSave); - - S session = this.repository.getSession(sessionToSave.getId()); - - assertThat(session.getId()).isEqualTo(sessionToSave.getId()); - assertThat(session.getMaxInactiveIntervalInSeconds()).isEqualTo(1800); - } - - @Configuration - @EnableHazelcastHttpSession(sessionMapName = "my-sessions") - static class HazelcastSessionXmlConfigCustomMapName { - - @Bean - public HazelcastInstance embeddedHazelcast() { - Config hazelcastConfig = new ClasspathXmlConfig( - "org/springframework/session/hazelcast/config/annotation/web/http/hazelcast-custom-map-name.xml"); - NetworkConfig netConfig = new NetworkConfig(); - netConfig.setPort(SocketUtils.findAvailableTcpPort()); - hazelcastConfig.setNetworkConfig(netConfig); - return Hazelcast.newHazelcastInstance(hazelcastConfig); - } - } - } - - @RunWith(SpringJUnit4ClassRunner.class) - @ContextConfiguration - @WebAppConfiguration - public static class CustomXmlMapNameAndIdleTest { - - @Autowired - private SessionRepository repository; - - @Test - public void saveSessionTest() throws InterruptedException { - - S sessionToSave = this.repository.createSession(); - - this.repository.save(sessionToSave); - - S session = this.repository.getSession(sessionToSave.getId()); - - assertThat(session.getId()).isEqualTo(sessionToSave.getId()); - assertThat(session.getMaxInactiveIntervalInSeconds()).isEqualTo(1200); - } - - @Configuration - @EnableHazelcastHttpSession(sessionMapName = "test-sessions", maxInactiveIntervalInSeconds = 1200) - static class HazelcastSessionXmlConfigCustomMapNameAndIdle { - - @Bean - public HazelcastInstance embeddedHazelcast() { - Config hazelcastConfig = new ClasspathXmlConfig( - "org/springframework/session/hazelcast/config/annotation/web/http/hazelcast-custom-idle-time-map-name.xml"); - NetworkConfig netConfig = new NetworkConfig(); - netConfig.setPort(SocketUtils.findAvailableTcpPort()); - hazelcastConfig.setNetworkConfig(netConfig); - return Hazelcast.newHazelcastInstance(hazelcastConfig); - } - } - } - -} diff --git a/spring-session/src/integration-test/java/org/springframework/session/jdbc/AbstractJdbcOperationsSessionRepositoryITests.java b/spring-session/src/integration-test/java/org/springframework/session/jdbc/AbstractJdbcOperationsSessionRepositoryITests.java deleted file mode 100644 index c049e80..0000000 --- a/spring-session/src/integration-test/java/org/springframework/session/jdbc/AbstractJdbcOperationsSessionRepositoryITests.java +++ /dev/null @@ -1,579 +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.jdbc; - -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.TimeUnit; - -import javax.sql.DataSource; - -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.jdbc.datasource.DataSourceTransactionManager; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.authority.AuthorityUtils; -import org.springframework.security.core.context.SecurityContext; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.session.ExpiringSession; -import org.springframework.session.FindByIndexNameSessionRepository; -import org.springframework.session.MapSession; -import org.springframework.session.Session; -import org.springframework.session.jdbc.config.annotation.web.http.EnableJdbcHttpSession; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.springframework.test.context.web.WebAppConfiguration; -import org.springframework.transaction.PlatformTransactionManager; -import org.springframework.transaction.annotation.Transactional; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Abstract base class for {@link JdbcOperationsSessionRepository} integration tests. - * - * @author Vedran Pavic - * @since 1.2.0 - */ -@WebAppConfiguration -@ContextConfiguration -@RunWith(SpringJUnit4ClassRunner.class) -public abstract class AbstractJdbcOperationsSessionRepositoryITests { - - private static final String SPRING_SECURITY_CONTEXT = "SPRING_SECURITY_CONTEXT"; - - private static final String INDEX_NAME = FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME; - - @Autowired - private JdbcOperationsSessionRepository repository; - - private SecurityContext context; - - private SecurityContext changedContext; - - @Before - public void setup() throws Exception { - this.context = SecurityContextHolder.createEmptyContext(); - this.context.setAuthentication( - new UsernamePasswordAuthenticationToken("username-" + UUID.randomUUID(), - "na", AuthorityUtils.createAuthorityList("ROLE_USER"))); - - this.changedContext = SecurityContextHolder.createEmptyContext(); - this.changedContext.setAuthentication(new UsernamePasswordAuthenticationToken( - "changedContext-" + UUID.randomUUID(), "na", - AuthorityUtils.createAuthorityList("ROLE_USER"))); - } - - @Test - public void saves() throws InterruptedException { - String username = "saves-" + System.currentTimeMillis(); - - JdbcOperationsSessionRepository.JdbcSession toSave = this.repository - .createSession(); - String expectedAttributeName = "a"; - String expectedAttributeValue = "b"; - toSave.setAttribute(expectedAttributeName, expectedAttributeValue); - Authentication toSaveToken = new UsernamePasswordAuthenticationToken(username, - "password", AuthorityUtils.createAuthorityList("ROLE_USER")); - SecurityContext toSaveContext = SecurityContextHolder.createEmptyContext(); - toSaveContext.setAuthentication(toSaveToken); - toSave.setAttribute(SPRING_SECURITY_CONTEXT, toSaveContext); - toSave.setAttribute(INDEX_NAME, username); - - this.repository.save(toSave); - - Session session = this.repository.getSession(toSave.getId()); - - assertThat(session.getId()).isEqualTo(toSave.getId()); - assertThat(session.getAttributeNames()).isEqualTo(toSave.getAttributeNames()); - assertThat(session.getAttribute(expectedAttributeName)) - .isEqualTo(toSave.getAttribute(expectedAttributeName)); - - this.repository.delete(toSave.getId()); - - assertThat(this.repository.getSession(toSave.getId())).isNull(); - } - - @Test - @Transactional(readOnly = true) - public void savesInReadOnlyTransaction() { - JdbcOperationsSessionRepository.JdbcSession toSave = this.repository - .createSession(); - - this.repository.save(toSave); - } - - @Test - public void putAllOnSingleAttrDoesNotRemoveOld() { - JdbcOperationsSessionRepository.JdbcSession toSave = this.repository - .createSession(); - toSave.setAttribute("a", "b"); - - this.repository.save(toSave); - toSave = this.repository.getSession(toSave.getId()); - - toSave.setAttribute("1", "2"); - - this.repository.save(toSave); - toSave = this.repository.getSession(toSave.getId()); - - Session session = this.repository.getSession(toSave.getId()); - assertThat(session.getAttributeNames().size()).isEqualTo(2); - assertThat(session.getAttribute("a")).isEqualTo("b"); - assertThat(session.getAttribute("1")).isEqualTo("2"); - - this.repository.delete(toSave.getId()); - } - - @Test - public void updateLastAccessedTime() { - JdbcOperationsSessionRepository.JdbcSession toSave = this.repository - .createSession(); - toSave.setLastAccessedTime(System.currentTimeMillis() - - (MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS * 1000 + 1000)); - - this.repository.save(toSave); - - long lastAccessedTime = System.currentTimeMillis(); - toSave.setLastAccessedTime(lastAccessedTime); - this.repository.save(toSave); - - ExpiringSession session = this.repository.getSession(toSave.getId()); - - assertThat(session).isNotNull(); - assertThat(session.isExpired()).isFalse(); - assertThat(session.getLastAccessedTime()).isEqualTo(lastAccessedTime); - } - - @Test - public void findByPrincipalName() throws Exception { - String principalName = "findByPrincipalName" + UUID.randomUUID(); - JdbcOperationsSessionRepository.JdbcSession toSave = this.repository - .createSession(); - toSave.setAttribute(INDEX_NAME, principalName); - - this.repository.save(toSave); - - Map findByPrincipalName = this.repository - .findByIndexNameAndIndexValue(INDEX_NAME, principalName); - - assertThat(findByPrincipalName).hasSize(1); - assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId()); - - this.repository.delete(toSave.getId()); - - findByPrincipalName = this.repository.findByIndexNameAndIndexValue(INDEX_NAME, - principalName); - - assertThat(findByPrincipalName).hasSize(0); - assertThat(findByPrincipalName.keySet()).doesNotContain(toSave.getId()); - } - - @Test - public void findByPrincipalNameExpireRemovesIndex() throws Exception { - String principalName = "findByPrincipalNameExpireRemovesIndex" - + UUID.randomUUID(); - JdbcOperationsSessionRepository.JdbcSession toSave = this.repository - .createSession(); - toSave.setAttribute(INDEX_NAME, principalName); - toSave.setLastAccessedTime(System.currentTimeMillis() - - (MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS * 1000 + 1000)); - - this.repository.save(toSave); - this.repository.cleanUpExpiredSessions(); - - Map findByPrincipalName = this.repository - .findByIndexNameAndIndexValue(INDEX_NAME, principalName); - - assertThat(findByPrincipalName).hasSize(0); - assertThat(findByPrincipalName.keySet()).doesNotContain(toSave.getId()); - } - - @Test - public void findByPrincipalNameNoPrincipalNameChange() throws Exception { - String principalName = "findByPrincipalNameNoPrincipalNameChange" - + UUID.randomUUID(); - JdbcOperationsSessionRepository.JdbcSession toSave = this.repository - .createSession(); - toSave.setAttribute(INDEX_NAME, principalName); - - this.repository.save(toSave); - - toSave.setAttribute("other", "value"); - this.repository.save(toSave); - - Map findByPrincipalName = this.repository - .findByIndexNameAndIndexValue(INDEX_NAME, principalName); - - assertThat(findByPrincipalName).hasSize(1); - assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId()); - } - - @Test - public void findByPrincipalNameNoPrincipalNameChangeReload() throws Exception { - String principalName = "findByPrincipalNameNoPrincipalNameChangeReload" - + UUID.randomUUID(); - JdbcOperationsSessionRepository.JdbcSession toSave = this.repository - .createSession(); - toSave.setAttribute(INDEX_NAME, principalName); - - this.repository.save(toSave); - - toSave = this.repository.getSession(toSave.getId()); - - toSave.setAttribute("other", "value"); - this.repository.save(toSave); - - Map findByPrincipalName = this.repository - .findByIndexNameAndIndexValue(INDEX_NAME, principalName); - - assertThat(findByPrincipalName).hasSize(1); - assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId()); - } - - @Test - public void findByDeletedPrincipalName() throws Exception { - String principalName = "findByDeletedPrincipalName" + UUID.randomUUID(); - JdbcOperationsSessionRepository.JdbcSession toSave = this.repository - .createSession(); - toSave.setAttribute(INDEX_NAME, principalName); - - this.repository.save(toSave); - - toSave.setAttribute(INDEX_NAME, null); - this.repository.save(toSave); - - Map findByPrincipalName = this.repository - .findByIndexNameAndIndexValue(INDEX_NAME, principalName); - - assertThat(findByPrincipalName).isEmpty(); - } - - @Test - public void findByChangedPrincipalName() throws Exception { - String principalName = "findByChangedPrincipalName" + UUID.randomUUID(); - String principalNameChanged = "findByChangedPrincipalName" + UUID.randomUUID(); - JdbcOperationsSessionRepository.JdbcSession toSave = this.repository - .createSession(); - toSave.setAttribute(INDEX_NAME, principalName); - - this.repository.save(toSave); - - toSave.setAttribute(INDEX_NAME, principalNameChanged); - this.repository.save(toSave); - - Map findByPrincipalName = this.repository - .findByIndexNameAndIndexValue(INDEX_NAME, principalName); - assertThat(findByPrincipalName).isEmpty(); - - findByPrincipalName = this.repository.findByIndexNameAndIndexValue(INDEX_NAME, - principalNameChanged); - - assertThat(findByPrincipalName).hasSize(1); - assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId()); - } - - @Test - public void findByDeletedPrincipalNameReload() throws Exception { - String principalName = "findByDeletedPrincipalName" + UUID.randomUUID(); - JdbcOperationsSessionRepository.JdbcSession toSave = this.repository - .createSession(); - toSave.setAttribute(INDEX_NAME, principalName); - - this.repository.save(toSave); - - JdbcOperationsSessionRepository.JdbcSession getSession = this.repository - .getSession(toSave.getId()); - getSession.setAttribute(INDEX_NAME, null); - this.repository.save(getSession); - - Map findByPrincipalName = this.repository - .findByIndexNameAndIndexValue(INDEX_NAME, principalName); - - assertThat(findByPrincipalName).isEmpty(); - } - - @Test - public void findByChangedPrincipalNameReload() throws Exception { - String principalName = "findByChangedPrincipalName" + UUID.randomUUID(); - String principalNameChanged = "findByChangedPrincipalName" + UUID.randomUUID(); - JdbcOperationsSessionRepository.JdbcSession toSave = this.repository - .createSession(); - toSave.setAttribute(INDEX_NAME, principalName); - - this.repository.save(toSave); - - JdbcOperationsSessionRepository.JdbcSession getSession = this.repository - .getSession(toSave.getId()); - - getSession.setAttribute(INDEX_NAME, principalNameChanged); - this.repository.save(getSession); - - Map findByPrincipalName = this.repository - .findByIndexNameAndIndexValue(INDEX_NAME, principalName); - assertThat(findByPrincipalName).isEmpty(); - - findByPrincipalName = this.repository.findByIndexNameAndIndexValue(INDEX_NAME, - principalNameChanged); - - assertThat(findByPrincipalName).hasSize(1); - assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId()); - } - - @Test - public void findBySecurityPrincipalName() throws Exception { - JdbcOperationsSessionRepository.JdbcSession toSave = this.repository - .createSession(); - toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.context); - - this.repository.save(toSave); - - Map findByPrincipalName = this.repository - .findByIndexNameAndIndexValue(INDEX_NAME, getSecurityName()); - - assertThat(findByPrincipalName).hasSize(1); - assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId()); - - this.repository.delete(toSave.getId()); - - findByPrincipalName = this.repository.findByIndexNameAndIndexValue(INDEX_NAME, - getSecurityName()); - - assertThat(findByPrincipalName).hasSize(0); - assertThat(findByPrincipalName.keySet()).doesNotContain(toSave.getId()); - } - - @Test - public void findBySecurityPrincipalNameExpireRemovesIndex() throws Exception { - JdbcOperationsSessionRepository.JdbcSession toSave = this.repository - .createSession(); - toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.context); - toSave.setLastAccessedTime(System.currentTimeMillis() - - (MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS * 1000 + 1000)); - - this.repository.save(toSave); - this.repository.cleanUpExpiredSessions(); - - Map findByPrincipalName = this.repository - .findByIndexNameAndIndexValue(INDEX_NAME, getSecurityName()); - - assertThat(findByPrincipalName).hasSize(0); - assertThat(findByPrincipalName.keySet()).doesNotContain(toSave.getId()); - } - - @Test - public void findByPrincipalNameNoSecurityPrincipalNameChange() throws Exception { - JdbcOperationsSessionRepository.JdbcSession toSave = this.repository - .createSession(); - toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.context); - - this.repository.save(toSave); - - toSave.setAttribute("other", "value"); - this.repository.save(toSave); - - Map findByPrincipalName = this.repository - .findByIndexNameAndIndexValue(INDEX_NAME, getSecurityName()); - - assertThat(findByPrincipalName).hasSize(1); - assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId()); - } - - @Test - public void findByPrincipalNameNoSecurityPrincipalNameChangeReload() - throws Exception { - JdbcOperationsSessionRepository.JdbcSession toSave = this.repository - .createSession(); - toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.context); - - this.repository.save(toSave); - - toSave = this.repository.getSession(toSave.getId()); - - toSave.setAttribute("other", "value"); - this.repository.save(toSave); - - Map findByPrincipalName = this.repository - .findByIndexNameAndIndexValue(INDEX_NAME, getSecurityName()); - - assertThat(findByPrincipalName).hasSize(1); - assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId()); - } - - @Test - public void findByDeletedSecurityPrincipalName() throws Exception { - JdbcOperationsSessionRepository.JdbcSession toSave = this.repository - .createSession(); - toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.context); - - this.repository.save(toSave); - - toSave.setAttribute(SPRING_SECURITY_CONTEXT, null); - this.repository.save(toSave); - - Map findByPrincipalName = this.repository - .findByIndexNameAndIndexValue(INDEX_NAME, getSecurityName()); - - assertThat(findByPrincipalName).isEmpty(); - } - - @Test - public void findByChangedSecurityPrincipalName() throws Exception { - JdbcOperationsSessionRepository.JdbcSession toSave = this.repository - .createSession(); - toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.context); - - this.repository.save(toSave); - - toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.changedContext); - this.repository.save(toSave); - - Map findByPrincipalName = this.repository - .findByIndexNameAndIndexValue(INDEX_NAME, getSecurityName()); - assertThat(findByPrincipalName).isEmpty(); - - findByPrincipalName = this.repository.findByIndexNameAndIndexValue(INDEX_NAME, - getChangedSecurityName()); - - assertThat(findByPrincipalName).hasSize(1); - assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId()); - } - - @Test - public void findByDeletedSecurityPrincipalNameReload() throws Exception { - JdbcOperationsSessionRepository.JdbcSession toSave = this.repository - .createSession(); - toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.context); - - this.repository.save(toSave); - - JdbcOperationsSessionRepository.JdbcSession getSession = this.repository - .getSession(toSave.getId()); - getSession.setAttribute(INDEX_NAME, null); - this.repository.save(getSession); - - Map findByPrincipalName = this.repository - .findByIndexNameAndIndexValue(INDEX_NAME, getChangedSecurityName()); - - assertThat(findByPrincipalName).isEmpty(); - } - - @Test - public void findByChangedSecurityPrincipalNameReload() throws Exception { - JdbcOperationsSessionRepository.JdbcSession toSave = this.repository - .createSession(); - toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.context); - - this.repository.save(toSave); - - JdbcOperationsSessionRepository.JdbcSession getSession = this.repository - .getSession(toSave.getId()); - - getSession.setAttribute(SPRING_SECURITY_CONTEXT, this.changedContext); - this.repository.save(getSession); - - Map findByPrincipalName = this.repository - .findByIndexNameAndIndexValue(INDEX_NAME, getSecurityName()); - assertThat(findByPrincipalName).isEmpty(); - - findByPrincipalName = this.repository.findByIndexNameAndIndexValue(INDEX_NAME, - getChangedSecurityName()); - - assertThat(findByPrincipalName).hasSize(1); - assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId()); - } - - @Test - public void cleanupInactiveSessionsUsingRepositoryDefinedInterval() { - JdbcOperationsSessionRepository.JdbcSession session = this.repository - .createSession(); - - this.repository.save(session); - - assertThat(this.repository.getSession(session.getId())).isNotNull(); - - this.repository.cleanUpExpiredSessions(); - - assertThat(this.repository.getSession(session.getId())).isNotNull(); - - long now = System.currentTimeMillis(); - - session.setLastAccessedTime(now - TimeUnit.MINUTES.toMillis(10)); - this.repository.save(session); - this.repository.cleanUpExpiredSessions(); - - assertThat(this.repository.getSession(session.getId())).isNotNull(); - - session.setLastAccessedTime(now - TimeUnit.MINUTES.toMillis(30)); - this.repository.save(session); - this.repository.cleanUpExpiredSessions(); - - assertThat(this.repository.getSession(session.getId())).isNull(); - } - - // gh-580 - @Test - public void cleanupInactiveSessionsUsingSessionDefinedInterval() { - JdbcOperationsSessionRepository.JdbcSession session = this.repository - .createSession(); - session.setMaxInactiveIntervalInSeconds((int) TimeUnit.MINUTES.toSeconds(45)); - - this.repository.save(session); - - assertThat(this.repository.getSession(session.getId())).isNotNull(); - - this.repository.cleanUpExpiredSessions(); - - assertThat(this.repository.getSession(session.getId())).isNotNull(); - - long now = System.currentTimeMillis(); - - session.setLastAccessedTime(now - TimeUnit.MINUTES.toMillis(40)); - this.repository.save(session); - this.repository.cleanUpExpiredSessions(); - - assertThat(this.repository.getSession(session.getId())).isNotNull(); - - session.setLastAccessedTime(now - TimeUnit.MINUTES.toMillis(50)); - this.repository.save(session); - this.repository.cleanUpExpiredSessions(); - - assertThat(this.repository.getSession(session.getId())).isNull(); - } - - private String getSecurityName() { - return this.context.getAuthentication().getName(); - } - - private String getChangedSecurityName() { - return this.changedContext.getAuthentication().getName(); - } - - @EnableJdbcHttpSession - protected static class BaseConfig { - - @Bean - public PlatformTransactionManager transactionManager(DataSource dataSource) { - return new DataSourceTransactionManager(dataSource); - } - - } -} diff --git a/spring-session/src/integration-test/java/org/springframework/session/jdbc/DerbyJdbcOperationsSessionRepositoryITests.java b/spring-session/src/integration-test/java/org/springframework/session/jdbc/DerbyJdbcOperationsSessionRepositoryITests.java deleted file mode 100644 index ac33711..0000000 --- a/spring-session/src/integration-test/java/org/springframework/session/jdbc/DerbyJdbcOperationsSessionRepositoryITests.java +++ /dev/null @@ -1,54 +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.jdbc; - -import org.junit.runner.RunWith; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase; -import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; -import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.springframework.test.context.web.WebAppConfiguration; - -/** - * Integration tests for {@link JdbcOperationsSessionRepository} using Derby database. - * - * @author Vedran Pavic - */ -@RunWith(SpringJUnit4ClassRunner.class) -@WebAppConfiguration -@ContextConfiguration -public class DerbyJdbcOperationsSessionRepositoryITests - extends AbstractJdbcOperationsSessionRepositoryITests { - - @Configuration - static class Config extends BaseConfig { - - @Bean - public EmbeddedDatabase dataSource() { - return new EmbeddedDatabaseBuilder() - .setType(EmbeddedDatabaseType.DERBY) - .addScript("org/springframework/session/jdbc/schema-derby.sql") - .build(); - } - - } - -} diff --git a/spring-session/src/integration-test/java/org/springframework/session/jdbc/H2JdbcOperationsSessionRepositoryITests.java b/spring-session/src/integration-test/java/org/springframework/session/jdbc/H2JdbcOperationsSessionRepositoryITests.java deleted file mode 100644 index 2b3f18d..0000000 --- a/spring-session/src/integration-test/java/org/springframework/session/jdbc/H2JdbcOperationsSessionRepositoryITests.java +++ /dev/null @@ -1,54 +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.jdbc; - -import org.junit.runner.RunWith; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase; -import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; -import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.springframework.test.context.web.WebAppConfiguration; - -/** - * Integration tests for {@link JdbcOperationsSessionRepository} using H2 database. - * - * @author Vedran Pavic - */ -@RunWith(SpringJUnit4ClassRunner.class) -@WebAppConfiguration -@ContextConfiguration -public class H2JdbcOperationsSessionRepositoryITests - extends AbstractJdbcOperationsSessionRepositoryITests { - - @Configuration - static class Config extends BaseConfig { - - @Bean - public EmbeddedDatabase dataSource() { - return new EmbeddedDatabaseBuilder() - .setType(EmbeddedDatabaseType.H2) - .addScript("org/springframework/session/jdbc/schema-h2.sql") - .build(); - } - - } - -} diff --git a/spring-session/src/integration-test/java/org/springframework/session/jdbc/HsqldbJdbcOperationsSessionRepositoryITests.java b/spring-session/src/integration-test/java/org/springframework/session/jdbc/HsqldbJdbcOperationsSessionRepositoryITests.java deleted file mode 100644 index bad6d4b..0000000 --- a/spring-session/src/integration-test/java/org/springframework/session/jdbc/HsqldbJdbcOperationsSessionRepositoryITests.java +++ /dev/null @@ -1,54 +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.jdbc; - -import org.junit.runner.RunWith; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase; -import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; -import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.springframework.test.context.web.WebAppConfiguration; - -/** - * Integration tests for {@link JdbcOperationsSessionRepository} using HSQLDB database. - * - * @author Vedran Pavic - */ -@RunWith(SpringJUnit4ClassRunner.class) -@WebAppConfiguration -@ContextConfiguration -public class HsqldbJdbcOperationsSessionRepositoryITests - extends AbstractJdbcOperationsSessionRepositoryITests { - - @Configuration - static class Config extends BaseConfig { - - @Bean - public EmbeddedDatabase dataSource() { - return new EmbeddedDatabaseBuilder() - .setType(EmbeddedDatabaseType.HSQL) - .addScript("org/springframework/session/jdbc/schema-hsqldb.sql") - .build(); - } - - } - -} diff --git a/spring-session/src/main/java/org/springframework/session/ExpiringSession.java b/spring-session/src/main/java/org/springframework/session/ExpiringSession.java deleted file mode 100644 index ff408ed..0000000 --- a/spring-session/src/main/java/org/springframework/session/ExpiringSession.java +++ /dev/null @@ -1,80 +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; - -/** - * A {@link Session} that contains additional attributes that are useful for determining - * if a session is expired. - * - * @author Rob Winch - * @since 1.0 - */ -public interface ExpiringSession extends Session { - - /** - * Gets the time when this session was created in milliseconds since midnight of - * 1/1/1970 GMT. - * - * @return the time when this session was created in milliseconds since midnight of - * 1/1/1970 GMT. - */ - long getCreationTime(); - - /** - * Sets the last accessed time in milliseconds since midnight of 1/1/1970 GMT. - * - * @param lastAccessedTime the last accessed time in milliseconds since midnight of - * 1/1/1970 GMT - */ - void setLastAccessedTime(long lastAccessedTime); - - /** - * Gets the last time this {@link Session} was accessed expressed in milliseconds - * since midnight of 1/1/1970 GMT. - * - * @return the last time the client sent a request associated with the session - * expressed in milliseconds since midnight of 1/1/1970 GMT - */ - long getLastAccessedTime(); - - /** - * Sets the maximum inactive interval in seconds between requests before this session - * will be invalidated. A negative time indicates that the session will never timeout. - * - * @param interval the number of seconds that the {@link Session} should be kept alive - * between client requests. - */ - void setMaxInactiveIntervalInSeconds(int interval); - - /** - * Gets the maximum inactive interval in seconds between requests before this session - * will be invalidated. A negative time indicates that the session will never timeout. - * - * @return the maximum inactive interval in seconds between requests before this - * session will be invalidated. A negative time indicates that the session will never - * timeout. - */ - int getMaxInactiveIntervalInSeconds(); - - /** - * Returns true if the session is expired. - * - * @return true if the session is expired, else false. - */ - boolean isExpired(); - -} diff --git a/spring-session/src/main/java/org/springframework/session/FindByIndexNameSessionRepository.java b/spring-session/src/main/java/org/springframework/session/FindByIndexNameSessionRepository.java deleted file mode 100644 index 7a3bba8..0000000 --- a/spring-session/src/main/java/org/springframework/session/FindByIndexNameSessionRepository.java +++ /dev/null @@ -1,63 +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; - -import java.util.Map; - -/** - * Extends a basic {@link SessionRepository} to allow finding a session id by the - * principal name. The principal name is defined by the {@link Session} attribute with the - * name {@link FindByIndexNameSessionRepository#PRINCIPAL_NAME_INDEX_NAME}. - * - * @param the type of Session being managed by this - * {@link FindByIndexNameSessionRepository} - * @author Rob Winch - */ -public interface FindByIndexNameSessionRepository - extends SessionRepository { - - /** - *

- * A common session attribute that contains the current principal name (i.e. - * username). - *

- * - *

- * It is the responsibility of the developer to ensure the attribute is populated - * since Spring Session is not aware of the authentication mechanism being used. - *

- * - * @since 1.1 - */ - String PRINCIPAL_NAME_INDEX_NAME = FindByIndexNameSessionRepository.class.getName() - .concat(".PRINCIPAL_NAME_INDEX_NAME"); - - /** - * Find a Map of the session id to the {@link Session} of all sessions that contain - * the session attribute with the name - * {@link FindByIndexNameSessionRepository#PRINCIPAL_NAME_INDEX_NAME} and the value of - * the specified principal name. - * - * @param indexName the name if the index (i.e. - * {@link FindByIndexNameSessionRepository#PRINCIPAL_NAME_INDEX_NAME}) - * @param indexValue the value of the index to search for. - * @return a Map (never null) of the session id to the {@link Session} of all sessions - * that contain the session specified index name and the value of the specified index - * name. If no results are found, an empty Map is returned. - */ - Map findByIndexNameAndIndexValue(String indexName, String indexValue); -} diff --git a/spring-session/src/main/java/org/springframework/session/MapSession.java b/spring-session/src/main/java/org/springframework/session/MapSession.java deleted file mode 100644 index 531772f..0000000 --- a/spring-session/src/main/java/org/springframework/session/MapSession.java +++ /dev/null @@ -1,190 +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; - -import java.io.Serializable; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.TimeUnit; - -/** - *

- * A {@link Session} implementation that is backed by a {@link java.util.Map}. The - * defaults for the properties are: - *

- *
    - *
  • id - a secure random generated id
  • - *
  • creationTime - the moment the {@link MapSession} was instantiated
  • - *
  • lastAccessedTime - the moment the {@link MapSession} was instantiated
  • - *
  • maxInactiveInterval - 30 minutes
  • - *
- * - *

- * This implementation has no synchronization, so it is best to use the copy constructor - * when working on multiple threads. - *

- * - * @author Rob Winch - * @since 1.0 - */ -public final class MapSession implements ExpiringSession, Serializable { - /** - * Default {@link #setMaxInactiveIntervalInSeconds(int)} (30 minutes). - */ - public static final int DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS = 1800; - - private String id; - private Map sessionAttrs = new HashMap(); - private long creationTime = System.currentTimeMillis(); - private long lastAccessedTime = this.creationTime; - - /** - * Defaults to 30 minutes. - */ - private int maxInactiveInterval = DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS; - - /** - * Creates a new instance with a secure randomly generated identifier. - */ - public MapSession() { - this(UUID.randomUUID().toString()); - } - - /** - * Creates a new instance with the specified id. This is preferred to the default - * constructor when the id is known to prevent unnecessary consumption on entropy - * which can be slow. - * - * @param id the identifier to use - */ - public MapSession(String id) { - this.id = id; - } - - /** - * Creates a new instance from the provided {@link Session}. - * - * @param session the {@link Session} to initialize this {@link Session} with. Cannot - * be null. - */ - public MapSession(ExpiringSession session) { - if (session == null) { - throw new IllegalArgumentException("session cannot be null"); - } - this.id = session.getId(); - this.sessionAttrs = new HashMap( - session.getAttributeNames().size()); - for (String attrName : session.getAttributeNames()) { - Object attrValue = session.getAttribute(attrName); - this.sessionAttrs.put(attrName, attrValue); - } - this.lastAccessedTime = session.getLastAccessedTime(); - this.creationTime = session.getCreationTime(); - this.maxInactiveInterval = session.getMaxInactiveIntervalInSeconds(); - } - - public void setLastAccessedTime(long lastAccessedTime) { - this.lastAccessedTime = lastAccessedTime; - } - - public long getCreationTime() { - return this.creationTime; - } - - public String getId() { - return this.id; - } - - public long getLastAccessedTime() { - return this.lastAccessedTime; - } - - public void setMaxInactiveIntervalInSeconds(int interval) { - this.maxInactiveInterval = interval; - } - - public int getMaxInactiveIntervalInSeconds() { - return this.maxInactiveInterval; - } - - public boolean isExpired() { - return isExpired(System.currentTimeMillis()); - } - - boolean isExpired(long now) { - if (this.maxInactiveInterval < 0) { - return false; - } - return now - TimeUnit.SECONDS - .toMillis(this.maxInactiveInterval) >= this.lastAccessedTime; - } - - @SuppressWarnings("unchecked") - public T getAttribute(String attributeName) { - return (T) this.sessionAttrs.get(attributeName); - } - - public Set getAttributeNames() { - return this.sessionAttrs.keySet(); - } - - public void setAttribute(String attributeName, Object attributeValue) { - if (attributeValue == null) { - removeAttribute(attributeName); - } - else { - this.sessionAttrs.put(attributeName, attributeValue); - } - } - - public void removeAttribute(String attributeName) { - this.sessionAttrs.remove(attributeName); - } - - /** - * Sets the time that this {@link Session} was created in milliseconds since midnight - * of 1/1/1970 GMT. The default is when the {@link Session} was instantiated. - * @param creationTime the time that this {@link Session} was created in milliseconds - * since midnight of 1/1/1970 GMT. - */ - public void setCreationTime(long creationTime) { - this.creationTime = creationTime; - } - - /** - * Sets the identifier for this {@link Session}. The id should be a secure random - * generated value to prevent malicious users from guessing this value. The default is - * a secure random generated identifier. - * - * @param id the identifier for this session. - */ - public void setId(String id) { - this.id = id; - } - - public boolean equals(Object obj) { - return obj instanceof Session && this.id.equals(((Session) obj).getId()); - } - - public int hashCode() { - return this.id.hashCode(); - } - - private static final long serialVersionUID = 7160779239673823561L; -} diff --git a/spring-session/src/main/java/org/springframework/session/MapSessionRepository.java b/spring-session/src/main/java/org/springframework/session/MapSessionRepository.java deleted file mode 100644 index 1b1327c..0000000 --- a/spring-session/src/main/java/org/springframework/session/MapSessionRepository.java +++ /dev/null @@ -1,105 +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; - -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import org.springframework.session.events.SessionDeletedEvent; -import org.springframework.session.events.SessionExpiredEvent; - -/** - * A {@link SessionRepository} backed by a {@link java.util.Map} and that uses a - * {@link MapSession}. By default a {@link java.util.concurrent.ConcurrentHashMap} is - * used, but a custom {@link java.util.Map} can be injected to use distributed maps - * provided by NoSQL stores like Redis and Hazelcast. - * - *

- * The implementation does NOT support firing {@link SessionDeletedEvent} or - * {@link SessionExpiredEvent}. - *

- * - * @author Rob Winch - * @since 1.0 - */ -public class MapSessionRepository implements SessionRepository { - /** - * If non-null, this value is used to override - * {@link ExpiringSession#setMaxInactiveIntervalInSeconds(int)}. - */ - private Integer defaultMaxInactiveInterval; - - private final Map sessions; - - /** - * Creates an instance backed by a {@link java.util.concurrent.ConcurrentHashMap}. - */ - public MapSessionRepository() { - this(new ConcurrentHashMap()); - } - - /** - * Creates a new instance backed by the provided {@link java.util.Map}. This allows - * injecting a distributed {@link java.util.Map}. - * - * @param sessions the {@link java.util.Map} to use. Cannot be null. - */ - public MapSessionRepository(Map sessions) { - if (sessions == null) { - throw new IllegalArgumentException("sessions cannot be null"); - } - this.sessions = sessions; - } - - /** - * If non-null, this value is used to override - * {@link ExpiringSession#setMaxInactiveIntervalInSeconds(int)}. - * @param defaultMaxInactiveInterval the number of seconds that the {@link Session} - * should be kept alive between client requests. - */ - public void setDefaultMaxInactiveInterval(int defaultMaxInactiveInterval) { - this.defaultMaxInactiveInterval = Integer.valueOf(defaultMaxInactiveInterval); - } - - public void save(ExpiringSession session) { - this.sessions.put(session.getId(), new MapSession(session)); - } - - public ExpiringSession getSession(String id) { - ExpiringSession saved = this.sessions.get(id); - if (saved == null) { - return null; - } - if (saved.isExpired()) { - delete(saved.getId()); - return null; - } - return new MapSession(saved); - } - - public void delete(String id) { - this.sessions.remove(id); - } - - public ExpiringSession createSession() { - ExpiringSession result = new MapSession(); - if (this.defaultMaxInactiveInterval != null) { - result.setMaxInactiveIntervalInSeconds(this.defaultMaxInactiveInterval); - } - return result; - } -} diff --git a/spring-session/src/main/java/org/springframework/session/Session.java b/spring-session/src/main/java/org/springframework/session/Session.java deleted file mode 100644 index 0ab3f7a..0000000 --- a/spring-session/src/main/java/org/springframework/session/Session.java +++ /dev/null @@ -1,74 +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; - -import java.util.Set; - -/** - * Provides a way to identify a user in an agnostic way. This allows the session to be - * used by an HttpSession, WebSocket Session, or even non web related sessions. - * - * @author Rob Winch - * @since 1.0 - */ -public interface Session { - - /** - * Gets a unique string that identifies the {@link Session}. - * - * @return a unique string that identifies the {@link Session} - */ - String getId(); - - /** - * Gets the Object associated with the specified name or null if no Object is - * associated to that name. - * - * @param attributeName the name of the attribute to get - * @return the Object associated with the specified name or null if no Object is - * associated to that name - * @param The return type of the attribute - */ - T getAttribute(String attributeName); - - /** - * Gets the attribute names that have a value associated with it. Each value can be - * passed into {@link org.springframework.session.Session#getAttribute(String)} to - * obtain the attribute value. - * - * @return the attribute names that have a value associated with it. - * @see #getAttribute(String) - */ - Set getAttributeNames(); - - /** - * Sets the attribute value for the provided attribute name. If the attributeValue is - * null, it has the same result as removing the attribute with - * {@link org.springframework.session.Session#removeAttribute(String)} . - * - * @param attributeName the attribute name to set - * @param attributeValue the value of the attribute to set. If null, the attribute - * will be removed. - */ - void setAttribute(String attributeName, Object attributeValue); - - /** - * Removes the attribute with the provided attribute name. - * @param attributeName the name of the attribute to remove - */ - void removeAttribute(String attributeName); -} diff --git a/spring-session/src/main/java/org/springframework/session/SessionRepository.java b/spring-session/src/main/java/org/springframework/session/SessionRepository.java deleted file mode 100644 index 3061b75..0000000 --- a/spring-session/src/main/java/org/springframework/session/SessionRepository.java +++ /dev/null @@ -1,73 +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; - -/** - * A repository interface for managing {@link Session} instances. - * - * @param the {@link Session} type - * @author Rob Winch - * @since 1.0 - */ -public interface SessionRepository { - - /** - * Creates a new {@link Session} that is capable of being persisted by this - * {@link SessionRepository}. - * - *

- * This allows optimizations and customizations in how the {@link Session} is - * persisted. For example, the implementation returned might keep track of the changes - * ensuring that only the delta needs to be persisted on a save. - *

- * - * @return a new {@link Session} that is capable of being persisted by this - * {@link SessionRepository} - */ - S createSession(); - - /** - * Ensures the {@link Session} created by - * {@link org.springframework.session.SessionRepository#createSession()} is saved. - * - *

- * Some implementations may choose to save as the {@link Session} is updated by - * returning a {@link Session} that immediately persists any changes. In this case, - * this method may not actually do anything. - *

- * - * @param session the {@link Session} to save - */ - void save(S session); - - /** - * Gets the {@link Session} by the {@link Session#getId()} or null if no - * {@link Session} is found. - * - * @param id the {@link org.springframework.session.Session#getId()} to lookup - * @return the {@link Session} by the {@link Session#getId()} or null if no - * {@link Session} is found. - */ - S getSession(String id); - - /** - * Deletes the {@link Session} with the given {@link Session#getId()} or does nothing - * if the {@link Session} is not found. - * @param id the {@link org.springframework.session.Session#getId()} to delete - */ - void delete(String id); -} diff --git a/spring-session/src/main/java/org/springframework/session/config/annotation/web/http/EnableSpringHttpSession.java b/spring-session/src/main/java/org/springframework/session/config/annotation/web/http/EnableSpringHttpSession.java deleted file mode 100644 index cafb3b9..0000000 --- a/spring-session/src/main/java/org/springframework/session/config/annotation/web/http/EnableSpringHttpSession.java +++ /dev/null @@ -1,79 +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.config.annotation.web.http; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; -import org.springframework.session.SessionRepository; -import org.springframework.session.events.SessionCreatedEvent; -import org.springframework.session.events.SessionDestroyedEvent; - -/** - * Add this annotation to an {@code @Configuration} class to expose the - * SessionRepositoryFilter as a bean named "springSessionRepositoryFilter" and backed by a - * user provided implementation of {@link SessionRepository}. In order to leverage the - * annotation, a single {@link SessionRepository} bean must be provided. For example: - * - *
- * 
- * {@literal @Configuration}
- * {@literal @EnableSpringHttpSession}
- * public class SpringHttpSessionConfig {
- *
- *     {@literal @Bean}
- *     public MapSessionRepository sessionRepository() {
- *         return new MapSessionRepository();
- *     }
- *
- * }
- *  
- * - *

- * It is important to note that no infrastructure for session expirations is configured - * for you out of the box. This is because things like session expiration are highly - * implementation dependent. This means if you require cleaning up expired sessions, you - * are responsible for cleaning up the expired sessions. - *

- * - *

- * The following is provided for you with the base configuration: - *

- * - *
    - *
  • SessionRepositoryFilter - is responsible for wrapping the HttpServletRequest with - * an implementation of HttpSession that is backed by a SessionRepository
  • - *
  • SessionEventHttpSessionListenerAdapter - is responsible for translating Spring - * Session events into HttpSessionEvent. In order for it to work, the implementation of - * SessionRepository you provide must support {@link SessionCreatedEvent} and - * {@link SessionDestroyedEvent}.
  • - *
  • - *
- * - * @author Rob Winch - * @since 1.1 - */ -@Retention(java.lang.annotation.RetentionPolicy.RUNTIME) -@Target({ java.lang.annotation.ElementType.TYPE }) -@Documented -@Import(SpringHttpSessionConfiguration.class) -@Configuration -public @interface EnableSpringHttpSession { -} diff --git a/spring-session/src/main/java/org/springframework/session/config/annotation/web/http/SpringHttpSessionConfiguration.java b/spring-session/src/main/java/org/springframework/session/config/annotation/web/http/SpringHttpSessionConfiguration.java deleted file mode 100644 index 67efa27..0000000 --- a/spring-session/src/main/java/org/springframework/session/config/annotation/web/http/SpringHttpSessionConfiguration.java +++ /dev/null @@ -1,171 +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.config.annotation.web.http; - -import java.util.ArrayList; -import java.util.List; - -import javax.annotation.PostConstruct; -import javax.servlet.ServletContext; -import javax.servlet.http.HttpSessionListener; - -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.session.ExpiringSession; -import org.springframework.session.SessionRepository; -import org.springframework.session.events.SessionCreatedEvent; -import org.springframework.session.events.SessionDestroyedEvent; -import org.springframework.session.security.web.authentication.SpringSessionRememberMeServices; -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; -import org.springframework.util.ObjectUtils; - -/** - * Configures the basics for setting up Spring Session in a web environment. In order to - * use it, you must provide a {@link SessionRepository}. For example: - * - *
- * {@literal @Configuration}
- * {@literal @EnableSpringHttpSession}
- * public class SpringHttpSessionConfig {
- *
- *     {@literal @Bean}
- *     public MapSessionRepository sessionRepository() {
- *         return new MapSessionRepository();
- *     }
- *
- * }
- * 
- * - *

- * It is important to note that no infrastructure for session expirations is configured - * for you out of the box. This is because things like session expiration are highly - * implementation dependent. This means if you require cleaning up expired sessions, you - * are responsible for cleaning up the expired sessions. - *

- * - *

- * The following is provided for you with the base configuration: - *

- * - *
    - *
  • SessionRepositoryFilter - is responsible for wrapping the HttpServletRequest with - * an implementation of HttpSession that is backed by a SessionRepository
  • - *
  • SessionEventHttpSessionListenerAdapter - is responsible for translating Spring - * Session events into HttpSessionEvent. In order for it to work, the implementation of - * SessionRepository you provide must support {@link SessionCreatedEvent} and - * {@link SessionDestroyedEvent}.
  • - *
  • - *
- * - * @author Rob Winch - * @author Vedran Pavic - * @since 1.1 - * - * @see EnableSpringHttpSession - */ -@Configuration -public class SpringHttpSessionConfiguration implements ApplicationContextAware { - - private CookieHttpSessionStrategy defaultHttpSessionStrategy = new CookieHttpSessionStrategy(); - - private boolean usesSpringSessionRememberMeServices; - - private ServletContext servletContext; - - private CookieSerializer cookieSerializer; - - private HttpSessionStrategy httpSessionStrategy = this.defaultHttpSessionStrategy; - - private List httpSessionListeners = new ArrayList(); - - @PostConstruct - public void init() { - if (this.cookieSerializer != null) { - this.defaultHttpSessionStrategy.setCookieSerializer(this.cookieSerializer); - } - else if (this.usesSpringSessionRememberMeServices) { - DefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer(); - cookieSerializer.setRememberMeRequestAttribute( - SpringSessionRememberMeServices.REMEMBER_ME_LOGIN_ATTR); - this.defaultHttpSessionStrategy.setCookieSerializer(cookieSerializer); - } - } - - @Bean - public SessionEventHttpSessionListenerAdapter sessionEventHttpSessionListenerAdapter() { - return new SessionEventHttpSessionListenerAdapter(this.httpSessionListeners); - } - - @Bean - public SessionRepositoryFilter springSessionRepositoryFilter( - SessionRepository sessionRepository) { - SessionRepositoryFilter sessionRepositoryFilter = new SessionRepositoryFilter( - sessionRepository); - sessionRepositoryFilter.setServletContext(this.servletContext); - if (this.httpSessionStrategy instanceof MultiHttpSessionStrategy) { - sessionRepositoryFilter.setHttpSessionStrategy( - (MultiHttpSessionStrategy) this.httpSessionStrategy); - } - else { - sessionRepositoryFilter.setHttpSessionStrategy(this.httpSessionStrategy); - } - return sessionRepositoryFilter; - } - - public void setApplicationContext(ApplicationContext applicationContext) - throws BeansException { - if (ClassUtils.isPresent( - "org.springframework.security.web.authentication.RememberMeServices", - null)) { - this.usesSpringSessionRememberMeServices = !ObjectUtils - .isEmpty(applicationContext - .getBeanNamesForType(SpringSessionRememberMeServices.class)); - } - } - - @Autowired(required = false) - public void setServletContext(ServletContext servletContext) { - this.servletContext = servletContext; - } - - @Autowired(required = false) - public void setCookieSerializer(CookieSerializer cookieSerializer) { - this.cookieSerializer = cookieSerializer; - } - - @Autowired(required = false) - public void setHttpSessionStrategy(HttpSessionStrategy httpSessionStrategy) { - this.httpSessionStrategy = httpSessionStrategy; - } - - @Autowired(required = false) - public void setHttpSessionListeners(List listeners) { - this.httpSessionListeners = listeners; - } - -} diff --git a/spring-session/src/main/java/org/springframework/session/data/redis/RedisFlushMode.java b/spring-session/src/main/java/org/springframework/session/data/redis/RedisFlushMode.java deleted file mode 100644 index aebacaf..0000000 --- a/spring-session/src/main/java/org/springframework/session/data/redis/RedisFlushMode.java +++ /dev/null @@ -1,42 +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.data.redis; - -import org.springframework.session.SessionRepository; - -/** - * Specifies when to write to the backing Redis instance. - * - * @author Rob Winch - * @since 1.1 - */ -public enum RedisFlushMode { - /** - * Only writes to Redis when - * {@link SessionRepository#save(org.springframework.session.Session)} is invoked. In - * a web environment this is typically done as soon as the HTTP response is committed. - */ - ON_SAVE, - - /** - * Writes to Redis as soon as possible. For example - * {@link SessionRepository#createSession()} will write the session to Redis. Another - * example is that setting an attribute on the session will also write to Redis - * immediately. - */ - IMMEDIATE -} diff --git a/spring-session/src/main/java/org/springframework/session/data/redis/RedisOperationsSessionRepository.java b/spring-session/src/main/java/org/springframework/session/data/redis/RedisOperationsSessionRepository.java deleted file mode 100644 index e3720fd..0000000 --- a/spring-session/src/main/java/org/springframework/session/data/redis/RedisOperationsSessionRepository.java +++ /dev/null @@ -1,831 +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.data.redis; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.TimeUnit; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.context.ApplicationEvent; -import org.springframework.context.ApplicationEventPublisher; -import org.springframework.data.redis.connection.Message; -import org.springframework.data.redis.connection.MessageListener; -import org.springframework.data.redis.connection.RedisConnectionFactory; -import org.springframework.data.redis.core.BoundHashOperations; -import org.springframework.data.redis.core.RedisOperations; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer; -import org.springframework.data.redis.serializer.RedisSerializer; -import org.springframework.data.redis.serializer.StringRedisSerializer; -import org.springframework.expression.Expression; -import org.springframework.expression.spel.standard.SpelExpressionParser; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.session.ExpiringSession; -import org.springframework.session.FindByIndexNameSessionRepository; -import org.springframework.session.MapSession; -import org.springframework.session.Session; -import org.springframework.session.events.SessionCreatedEvent; -import org.springframework.session.events.SessionDeletedEvent; -import org.springframework.session.events.SessionDestroyedEvent; -import org.springframework.session.events.SessionExpiredEvent; -import org.springframework.session.web.http.SessionRepositoryFilter; -import org.springframework.util.Assert; - -/** - *

- * A {@link org.springframework.session.SessionRepository} that is implemented using - * Spring Data's {@link org.springframework.data.redis.core.RedisOperations}. In a web - * environment, this is typically used in combination with {@link SessionRepositoryFilter} - * . This implementation supports {@link SessionDeletedEvent} and - * {@link SessionExpiredEvent} by implementing {@link MessageListener}. - *

- * - *

Creating a new instance

- * - * A typical example of how to create a new instance can be seen below: - * - *
- * JedisConnectionFactory factory = new JedisConnectionFactory();
- *
- * RedisOperationsSessionRepository redisSessionRepository = new RedisOperationsSessionRepository(factory);
- * 
- * - *

- * For additional information on how to create a RedisTemplate, refer to the - * - * Spring Data Redis Reference. - *

- * - *

Storage Details

- * - * The sections below outline how Redis is updated for each operation. An example of - * creating a new session can be found below. The subsequent sections describe the - * details. - * - *
- * HMSET spring:session:sessions:33fdd1b6-b496-4b33-9f7d-df96679d32fe creationTime 1404360000000 maxInactiveInterval 1800 lastAccessedTime 1404360000000 sessionAttr:attrName someAttrValue sessionAttr2:attrName someAttrValue2
- * EXPIRE spring:session:sessions:33fdd1b6-b496-4b33-9f7d-df96679d32fe 2100
- * APPEND spring:session:sessions:expires:33fdd1b6-b496-4b33-9f7d-df96679d32fe ""
- * EXPIRE spring:session:sessions:expires:33fdd1b6-b496-4b33-9f7d-df96679d32fe 1800
- * SADD spring:session:expirations:1439245080000 expires:33fdd1b6-b496-4b33-9f7d-df96679d32fe
- * EXPIRE spring:session:expirations1439245080000 2100
- * 
- * - *

Saving a Session

- * - *

- * Each session is stored in Redis as a - * Hash. Each session is set and - * updated using the HMSET command. An - * example of how each session is stored can be seen below. - *

- * - *
- * HMSET spring:session:sessions:33fdd1b6-b496-4b33-9f7d-df96679d32fe creationTime 1404360000000 maxInactiveInterval 1800 lastAccessedTime 1404360000000 sessionAttr:attrName someAttrValue sessionAttr:attrName2 someAttrValue2
- * 
- * - *

- * In this example, the session following statements are true about the session: - *

- *
    - *
  • The session id is 33fdd1b6-b496-4b33-9f7d-df96679d32fe
  • - *
  • The session was created at 1404360000000 in milliseconds since midnight of 1/1/1970 - * GMT.
  • - *
  • The session expires in 1800 seconds (30 minutes).
  • - *
  • The session was last accessed at 1404360000000 in milliseconds since midnight of - * 1/1/1970 GMT.
  • - *
  • The session has two attributes. The first is "attrName" with the value of - * "someAttrValue". The second session attribute is named "attrName2" with the value of - * "someAttrValue2".
  • - *
- * - * - *

Optimized Writes

- * - *

- * The {@link RedisSession} keeps track of the properties that have changed and only - * updates those. This means if an attribute is written once and read many times we only - * need to write that attribute once. For example, assume the session attribute - * "sessionAttr2" from earlier was updated. The following would be executed upon saving: - *

- * - *
- * HMSET spring:session:sessions:33fdd1b6-b496-4b33-9f7d-df96679d32fe sessionAttr:attrName2 newValue
- * 
- * - *

SessionCreatedEvent

- * - *

- * When a session is created an event is sent to Redis with the channel of - * "spring:session:channel:created:33fdd1b6-b496-4b33-9f7d-df96679d32fe" such that - * "33fdd1b6-b496-4b33-9f7d-df96679d32fe" is the sesion id. The body of the event will be - * the session that was created. - *

- * - *

- * If registered as a {@link MessageListener}, then - * {@link RedisOperationsSessionRepository} will then translate the Redis message into a - * {@link SessionCreatedEvent}. - *

- * - *

Expiration

- * - *

- * An expiration is associated to each session using the - * EXPIRE command based upon the - * {@link org.springframework.session.data.redis.RedisOperationsSessionRepository.RedisSession#getMaxInactiveIntervalInSeconds()} - * . For example: - *

- * - *
- * EXPIRE spring:session:sessions:33fdd1b6-b496-4b33-9f7d-df96679d32fe 2100
- * 
- * - *

- * You will note that the expiration that is set is 5 minutes after the session actually - * expires. This is necessary so that the value of the session can be accessed when the - * session expires. An expiration is set on the session itself five minutes after it - * actually expires to ensure it is cleaned up, but only after we perform any necessary - * processing. - *

- * - *

- * NOTE: The {@link #getSession(String)} method ensures that no expired sessions - * will be returned. This means there is no need to check the expiration before using a - * session - *

- * - *

- * Spring Session relies on the expired and delete - * keyspace notifications from Redis to - * fire a SessionDestroyedEvent. It is the SessionDestroyedEvent that ensures resources - * associated with the Session are cleaned up. For example, when using Spring Session's - * WebSocket support the Redis expired or delete event is what triggers any WebSocket - * connections associated with the session to be closed. - *

- * - *

- * Expiration is not tracked directly on the session key itself since this would mean the - * session data would no longer be available. Instead a special session expires key is - * used. In our example the expires key is: - *

- * - *
- * APPEND spring:session:sessions:expires:33fdd1b6-b496-4b33-9f7d-df96679d32fe ""
- * EXPIRE spring:session:sessions:expires:33fdd1b6-b496-4b33-9f7d-df96679d32fe 1800
- * 
- * - *

- * When a session expires key is deleted or expires, the keyspace notification triggers a - * lookup of the actual session and a {@link SessionDestroyedEvent} is fired. - *

- * - *

- * One problem with relying on Redis expiration exclusively is that Redis makes no - * guarantee of when the expired event will be fired if they key has not been accessed. - * Specifically the background task that Redis uses to clean up expired keys is a low - * priority task and may not trigger the key expiration. For additional details see - * Timing of expired events section in - * the Redis documentation. - *

- * - *

- * To circumvent the fact that expired events are not guaranteed to happen we can ensure - * that each key is accessed when it is expected to expire. This means that if the TTL is - * expired on the key, Redis will remove the key and fire the expired event when we try to - * access they key. - *

- * - *

- * For this reason, each session expiration is also tracked to the nearest minute. This - * allows a background task to access the potentially expired sessions to ensure that - * Redis expired events are fired in a more deterministic fashion. For example: - *

- * - *
- * SADD spring:session:expirations:1439245080000 expires:33fdd1b6-b496-4b33-9f7d-df96679d32fe
- * EXPIRE spring:session:expirations1439245080000 2100
- * 
- * - *

- * The background task will then use these mappings to explicitly request each session - * expires key. By accessing the key, rather than deleting it, we ensure that Redis - * deletes the key for us only if the TTL is expired. - *

- *

- * NOTE: We do not explicitly delete the keys since in some instances there may be - * a race condition that incorrectly identifies a key as expired when it is not. Short of - * using distributed locks (which would kill our performance) there is no way to ensure - * the consistency of the expiration mapping. By simply accessing the key, we ensure that - * the key is only removed if the TTL on that key is expired. - *

- * - * @author Rob Winch - * @since 1.0 - */ -public class RedisOperationsSessionRepository implements - FindByIndexNameSessionRepository, - MessageListener { - private static final Log logger = LogFactory - .getLog(RedisOperationsSessionRepository.class); - - private static final String SPRING_SECURITY_CONTEXT = "SPRING_SECURITY_CONTEXT"; - - static PrincipalNameResolver PRINCIPAL_NAME_RESOLVER = new PrincipalNameResolver(); - - /** - * The default prefix for each key and channel in Redis used by Spring Session. - */ - static final String DEFAULT_SPRING_SESSION_REDIS_PREFIX = "spring:session:"; - - /** - * The key in the Hash representing - * {@link org.springframework.session.ExpiringSession#getCreationTime()}. - */ - static final String CREATION_TIME_ATTR = "creationTime"; - - /** - * The key in the Hash representing - * {@link org.springframework.session.ExpiringSession#getMaxInactiveIntervalInSeconds()} - * . - */ - static final String MAX_INACTIVE_ATTR = "maxInactiveInterval"; - - /** - * The key in the Hash representing - * {@link org.springframework.session.ExpiringSession#getLastAccessedTime()}. - */ - static final String LAST_ACCESSED_ATTR = "lastAccessedTime"; - - /** - * The prefix of the key for used for session attributes. The suffix is the name of - * the session attribute. For example, if the session contained an attribute named - * attributeName, then there would be an entry in the hash named - * sessionAttr:attributeName that mapped to its value. - */ - static final String SESSION_ATTR_PREFIX = "sessionAttr:"; - - /** - * The prefix for every key used by Spring Session in Redis. - */ - private String keyPrefix = DEFAULT_SPRING_SESSION_REDIS_PREFIX; - - private final RedisOperations sessionRedisOperations; - - private final RedisSessionExpirationPolicy expirationPolicy; - - private ApplicationEventPublisher eventPublisher = new ApplicationEventPublisher() { - public void publishEvent(ApplicationEvent event) { - } - - public void publishEvent(Object event) { - } - }; - - /** - * If non-null, this value is used to override the default value for - * {@link RedisSession#setMaxInactiveIntervalInSeconds(int)}. - */ - private Integer defaultMaxInactiveInterval; - - private RedisSerializer defaultSerializer = new JdkSerializationRedisSerializer(); - - private RedisFlushMode redisFlushMode = RedisFlushMode.ON_SAVE; - - /** - * Allows creating an instance and uses a default {@link RedisOperations} for both - * managing the session and the expirations. - * - * @param redisConnectionFactory the {@link RedisConnectionFactory} to use. - */ - public RedisOperationsSessionRepository( - RedisConnectionFactory redisConnectionFactory) { - this(createDefaultTemplate(redisConnectionFactory)); - } - - /** - * Creates a new instance. For an example, refer to the class level javadoc. - * - * @param sessionRedisOperations The {@link RedisOperations} to use for managing the - * sessions. Cannot be null. - */ - public RedisOperationsSessionRepository( - RedisOperations sessionRedisOperations) { - Assert.notNull(sessionRedisOperations, "sessionRedisOperations cannot be null"); - this.sessionRedisOperations = sessionRedisOperations; - this.expirationPolicy = new RedisSessionExpirationPolicy(sessionRedisOperations, - this); - } - - /** - * Sets the {@link ApplicationEventPublisher} that is used to publish - * {@link SessionDestroyedEvent}. The default is to not publish a - * {@link SessionDestroyedEvent}. - * - * @param applicationEventPublisher the {@link ApplicationEventPublisher} that is used - * to publish {@link SessionDestroyedEvent}. Cannot be null. - */ - public void setApplicationEventPublisher( - ApplicationEventPublisher applicationEventPublisher) { - Assert.notNull(applicationEventPublisher, - "applicationEventPublisher cannot be null"); - this.eventPublisher = applicationEventPublisher; - } - - /** - * Sets the maximum inactive interval in seconds between requests before newly created - * sessions will be invalidated. A negative time indicates that the session will never - * timeout. The default is 1800 (30 minutes). - * - * @param defaultMaxInactiveInterval the number of seconds that the {@link Session} - * should be kept alive between client requests. - */ - public void setDefaultMaxInactiveInterval(int defaultMaxInactiveInterval) { - this.defaultMaxInactiveInterval = defaultMaxInactiveInterval; - } - - /** - * Sets the default redis serializer. Replaces default serializer which is based on - * {@link JdkSerializationRedisSerializer}. - * - * @param defaultSerializer the new default redis serializer - */ - public void setDefaultSerializer(RedisSerializer defaultSerializer) { - Assert.notNull(defaultSerializer, "defaultSerializer cannot be null"); - this.defaultSerializer = defaultSerializer; - } - - /** - * Sets the redis flush mode. Default flush mode is {@link RedisFlushMode#ON_SAVE}. - * - * @param redisFlushMode the new redis flush mode - */ - public void setRedisFlushMode(RedisFlushMode redisFlushMode) { - Assert.notNull(redisFlushMode, "redisFlushMode cannot be null"); - this.redisFlushMode = redisFlushMode; - } - - public void save(RedisSession session) { - session.saveDelta(); - if (session.isNew()) { - String sessionCreatedKey = getSessionCreatedChannel(session.getId()); - this.sessionRedisOperations.convertAndSend(sessionCreatedKey, session.delta); - session.setNew(false); - } - } - - @Scheduled(cron = "${spring.session.cleanup.cron.expression:0 * * * * *}") - public void cleanupExpiredSessions() { - this.expirationPolicy.cleanExpiredSessions(); - } - - public RedisSession getSession(String id) { - return getSession(id, false); - } - - public Map findByIndexNameAndIndexValue(String indexName, - String indexValue) { - if (!PRINCIPAL_NAME_INDEX_NAME.equals(indexName)) { - return Collections.emptyMap(); - } - String principalKey = getPrincipalKey(indexValue); - Set sessionIds = this.sessionRedisOperations.boundSetOps(principalKey) - .members(); - Map sessions = new HashMap( - sessionIds.size()); - for (Object id : sessionIds) { - RedisSession session = getSession((String) id); - if (session != null) { - sessions.put(session.getId(), session); - } - } - return sessions; - } - - /** - * Gets the session. - * @param id the session id - * @param allowExpired if true, will also include expired sessions that have not been - * deleted. If false, will ensure expired sessions are not returned. - * @return the Redis session - */ - private RedisSession getSession(String id, boolean allowExpired) { - Map entries = getSessionBoundHashOperations(id).entries(); - if (entries.isEmpty()) { - return null; - } - MapSession loaded = loadSession(id, entries); - if (!allowExpired && loaded.isExpired()) { - return null; - } - RedisSession result = new RedisSession(loaded); - result.originalLastAccessTime = loaded.getLastAccessedTime(); - return result; - } - - private MapSession loadSession(String id, Map entries) { - MapSession loaded = new MapSession(id); - for (Map.Entry entry : entries.entrySet()) { - String key = (String) entry.getKey(); - if (CREATION_TIME_ATTR.equals(key)) { - loaded.setCreationTime((Long) entry.getValue()); - } - else if (MAX_INACTIVE_ATTR.equals(key)) { - loaded.setMaxInactiveIntervalInSeconds((Integer) entry.getValue()); - } - else if (LAST_ACCESSED_ATTR.equals(key)) { - loaded.setLastAccessedTime((Long) entry.getValue()); - } - else if (key.startsWith(SESSION_ATTR_PREFIX)) { - loaded.setAttribute(key.substring(SESSION_ATTR_PREFIX.length()), - entry.getValue()); - } - } - return loaded; - } - - public void delete(String sessionId) { - RedisSession session = getSession(sessionId, true); - if (session == null) { - return; - } - - cleanupPrincipalIndex(session); - this.expirationPolicy.onDelete(session); - - String expireKey = getExpiredKey(session.getId()); - this.sessionRedisOperations.delete(expireKey); - - session.setMaxInactiveIntervalInSeconds(0); - save(session); - } - - public RedisSession createSession() { - RedisSession redisSession = new RedisSession(); - if (this.defaultMaxInactiveInterval != null) { - redisSession.setMaxInactiveIntervalInSeconds(this.defaultMaxInactiveInterval); - } - return redisSession; - } - - @SuppressWarnings("unchecked") - public void onMessage(Message message, byte[] pattern) { - byte[] messageChannel = message.getChannel(); - byte[] messageBody = message.getBody(); - if (messageChannel == null || messageBody == null) { - return; - } - - String channel = new String(messageChannel); - - if (channel.startsWith(getSessionCreatedChannelPrefix())) { - // TODO: is this thread safe? - Map loaded = (Map) this.defaultSerializer - .deserialize(message.getBody()); - handleCreated(loaded, channel); - return; - } - - String body = new String(messageBody); - if (!body.startsWith(getExpiredKeyPrefix())) { - return; - } - - boolean isDeleted = channel.endsWith(":del"); - if (isDeleted || channel.endsWith(":expired")) { - int beginIndex = body.lastIndexOf(":") + 1; - int endIndex = body.length(); - String sessionId = body.substring(beginIndex, endIndex); - - RedisSession session = getSession(sessionId, true); - - if (logger.isDebugEnabled()) { - logger.debug("Publishing SessionDestroyedEvent for session " + sessionId); - } - - cleanupPrincipalIndex(session); - - if (isDeleted) { - handleDeleted(sessionId, session); - } - else { - handleExpired(sessionId, session); - } - - return; - } - } - - private void cleanupPrincipalIndex(RedisSession session) { - if (session == null) { - return; - } - String sessionId = session.getId(); - String principal = PRINCIPAL_NAME_RESOLVER.resolvePrincipal(session); - if (principal != null) { - this.sessionRedisOperations.boundSetOps(getPrincipalKey(principal)) - .remove(sessionId); - } - } - - public void handleCreated(Map loaded, String channel) { - String id = channel.substring(channel.lastIndexOf(":") + 1); - ExpiringSession session = loadSession(id, loaded); - publishEvent(new SessionCreatedEvent(this, session)); - } - - private void handleDeleted(String sessionId, RedisSession session) { - if (session == null) { - publishEvent(new SessionDeletedEvent(this, sessionId)); - } - else { - publishEvent(new SessionDeletedEvent(this, session)); - } - } - - private void handleExpired(String sessionId, RedisSession session) { - if (session == null) { - publishEvent(new SessionExpiredEvent(this, sessionId)); - } - else { - publishEvent(new SessionExpiredEvent(this, session)); - } - } - - private void publishEvent(ApplicationEvent event) { - try { - this.eventPublisher.publishEvent(event); - } - catch (Throwable ex) { - logger.error("Error publishing " + event + ".", ex); - } - } - - public void setRedisKeyNamespace(String namespace) { - this.keyPrefix = DEFAULT_SPRING_SESSION_REDIS_PREFIX + namespace + ":"; - } - - /** - * Gets the Hash key for this session by prefixing it appropriately. - * - * @param sessionId the session id - * @return the Hash key for this session by prefixing it appropriately. - */ - String getSessionKey(String sessionId) { - return this.keyPrefix + "sessions:" + sessionId; - } - - String getPrincipalKey(String principalName) { - return this.keyPrefix + "index:" - + FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME + ":" - + principalName; - } - - String getExpirationsKey(long expiration) { - return this.keyPrefix + "expirations:" + expiration; - } - - private String getExpiredKey(String sessionId) { - return getExpiredKeyPrefix() + sessionId; - } - - private String getSessionCreatedChannel(String sessionId) { - return getSessionCreatedChannelPrefix() + sessionId; - } - - private String getExpiredKeyPrefix() { - return this.keyPrefix + "sessions:" + "expires:"; - } - - /** - * Gets the prefix for the channel that SessionCreatedEvent are published to. The - * suffix is the session id of the session that was created. - * - * @return the prefix for the channel that SessionCreatedEvent are published to - */ - public String getSessionCreatedChannelPrefix() { - return this.keyPrefix + "event:created:"; - } - - /** - * Gets the {@link BoundHashOperations} to operate on a {@link Session}. - * @param sessionId the id of the {@link Session} to work with - * @return the {@link BoundHashOperations} to operate on a {@link Session} - */ - private BoundHashOperations getSessionBoundHashOperations( - String sessionId) { - String key = getSessionKey(sessionId); - return this.sessionRedisOperations.boundHashOps(key); - } - - /** - * Gets the key for the specified session attribute. - * - * @param attributeName the attribute name - * @return the attribute key name - */ - static String getSessionAttrNameKey(String attributeName) { - return SESSION_ATTR_PREFIX + attributeName; - } - - private static RedisTemplate createDefaultTemplate( - RedisConnectionFactory connectionFactory) { - Assert.notNull(connectionFactory, "connectionFactory cannot be null"); - RedisTemplate template = new RedisTemplate(); - template.setKeySerializer(new StringRedisSerializer()); - template.setHashKeySerializer(new StringRedisSerializer()); - template.setConnectionFactory(connectionFactory); - template.afterPropertiesSet(); - return template; - } - - /** - * A custom implementation of {@link Session} that uses a {@link MapSession} as the - * basis for its mapping. It keeps track of any attributes that have changed. When - * {@link org.springframework.session.data.redis.RedisOperationsSessionRepository.RedisSession#saveDelta()} - * is invoked all the attributes that have been changed will be persisted. - * - * @author Rob Winch - * @since 1.0 - */ - final class RedisSession implements ExpiringSession { - private final MapSession cached; - private Long originalLastAccessTime; - private Map delta = new HashMap(); - private boolean isNew; - private String originalPrincipalName; - - /** - * Creates a new instance ensuring to mark all of the new attributes to be - * persisted in the next save operation. - */ - RedisSession() { - this(new MapSession()); - this.delta.put(CREATION_TIME_ATTR, getCreationTime()); - this.delta.put(MAX_INACTIVE_ATTR, getMaxInactiveIntervalInSeconds()); - this.delta.put(LAST_ACCESSED_ATTR, getLastAccessedTime()); - this.isNew = true; - this.flushImmediateIfNecessary(); - } - - /** - * Creates a new instance from the provided {@link MapSession}. - * - * @param cached the {@link MapSession} that represents the persisted session that - * was retrieved. Cannot be null. - */ - RedisSession(MapSession cached) { - Assert.notNull(cached, "MapSession cannot be null"); - this.cached = cached; - this.originalPrincipalName = PRINCIPAL_NAME_RESOLVER.resolvePrincipal(this); - } - - public void setNew(boolean isNew) { - this.isNew = isNew; - } - - public void setLastAccessedTime(long lastAccessedTime) { - this.cached.setLastAccessedTime(lastAccessedTime); - this.putAndFlush(LAST_ACCESSED_ATTR, getLastAccessedTime()); - } - - public boolean isExpired() { - return this.cached.isExpired(); - } - - public boolean isNew() { - return this.isNew; - } - - public long getCreationTime() { - return this.cached.getCreationTime(); - } - - public String getId() { - return this.cached.getId(); - } - - public long getLastAccessedTime() { - return this.cached.getLastAccessedTime(); - } - - public void setMaxInactiveIntervalInSeconds(int interval) { - this.cached.setMaxInactiveIntervalInSeconds(interval); - this.putAndFlush(MAX_INACTIVE_ATTR, getMaxInactiveIntervalInSeconds()); - } - - public int getMaxInactiveIntervalInSeconds() { - return this.cached.getMaxInactiveIntervalInSeconds(); - } - - public T getAttribute(String attributeName) { - return this.cached.getAttribute(attributeName); - } - - public Set getAttributeNames() { - return this.cached.getAttributeNames(); - } - - public void setAttribute(String attributeName, Object attributeValue) { - this.cached.setAttribute(attributeName, attributeValue); - this.putAndFlush(getSessionAttrNameKey(attributeName), attributeValue); - } - - public void removeAttribute(String attributeName) { - this.cached.removeAttribute(attributeName); - this.putAndFlush(getSessionAttrNameKey(attributeName), null); - } - - private void flushImmediateIfNecessary() { - if (RedisOperationsSessionRepository.this.redisFlushMode == RedisFlushMode.IMMEDIATE) { - saveDelta(); - } - } - - private void putAndFlush(String a, Object v) { - this.delta.put(a, v); - this.flushImmediateIfNecessary(); - } - - /** - * Saves any attributes that have been changed and updates the expiration of this - * session. - */ - private void saveDelta() { - if (this.delta.isEmpty()) { - return; - } - String sessionId = getId(); - getSessionBoundHashOperations(sessionId).putAll(this.delta); - String principalSessionKey = getSessionAttrNameKey( - FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME); - String securityPrincipalSessionKey = getSessionAttrNameKey( - SPRING_SECURITY_CONTEXT); - if (this.delta.containsKey(principalSessionKey) - || this.delta.containsKey(securityPrincipalSessionKey)) { - if (this.originalPrincipalName != null) { - String originalPrincipalRedisKey = getPrincipalKey( - this.originalPrincipalName); - RedisOperationsSessionRepository.this.sessionRedisOperations - .boundSetOps(originalPrincipalRedisKey).remove(sessionId); - } - String principal = PRINCIPAL_NAME_RESOLVER.resolvePrincipal(this); - this.originalPrincipalName = principal; - if (principal != null) { - String principalRedisKey = getPrincipalKey(principal); - RedisOperationsSessionRepository.this.sessionRedisOperations - .boundSetOps(principalRedisKey).add(sessionId); - } - } - - this.delta = new HashMap(this.delta.size()); - - Long originalExpiration = this.originalLastAccessTime == null ? null - : this.originalLastAccessTime + TimeUnit.SECONDS - .toMillis(getMaxInactiveIntervalInSeconds()); - RedisOperationsSessionRepository.this.expirationPolicy - .onExpirationUpdated(originalExpiration, this); - } - } - - /** - * Principal name resolver helper class. - */ - static class PrincipalNameResolver { - private SpelExpressionParser parser = new SpelExpressionParser(); - - public String resolvePrincipal(Session session) { - String principalName = session.getAttribute(PRINCIPAL_NAME_INDEX_NAME); - if (principalName != null) { - return principalName; - } - Object authentication = session.getAttribute(SPRING_SECURITY_CONTEXT); - if (authentication != null) { - Expression expression = this.parser - .parseExpression("authentication?.name"); - return expression.getValue(authentication, String.class); - } - return null; - } - - } -} diff --git a/spring-session/src/main/java/org/springframework/session/data/redis/RedisSessionExpirationPolicy.java b/spring-session/src/main/java/org/springframework/session/data/redis/RedisSessionExpirationPolicy.java deleted file mode 100644 index 706c034..0000000 --- a/spring-session/src/main/java/org/springframework/session/data/redis/RedisSessionExpirationPolicy.java +++ /dev/null @@ -1,173 +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.data.redis; - -import java.util.Calendar; -import java.util.Date; -import java.util.Set; -import java.util.concurrent.TimeUnit; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.data.redis.core.BoundSetOperations; -import org.springframework.data.redis.core.RedisOperations; -import org.springframework.session.ExpiringSession; -import org.springframework.session.data.redis.RedisOperationsSessionRepository.RedisSession; - -/** - * A strategy for expiring {@link RedisSession} instances. This performs two operations: - * - * Redis has no guarantees of when an expired session event will be fired. In order to - * ensure expired session events are processed in a timely fashion the expiration (rounded - * to the nearest minute) is mapped to all the sessions that expire at that time. Whenever - * {@link #cleanExpiredSessions()} is invoked, the sessions for the previous minute are - * then accessed to ensure they are deleted if expired. - * - * In some instances the {@link #cleanExpiredSessions()} method may not be not invoked for - * a specific time. For example, this may happen when a server is restarted. To account - * for this, the expiration on the Redis session is also set. - * - * @author Rob Winch - * @since 1.0 - */ -final class RedisSessionExpirationPolicy { - - private static final Log logger = LogFactory - .getLog(RedisSessionExpirationPolicy.class); - - private final RedisOperations redis; - - private final RedisOperationsSessionRepository redisSession; - - RedisSessionExpirationPolicy(RedisOperations sessionRedisOperations, - RedisOperationsSessionRepository redisSession) { - super(); - this.redis = sessionRedisOperations; - this.redisSession = redisSession; - } - - public void onDelete(ExpiringSession session) { - long toExpire = roundUpToNextMinute(expiresInMillis(session)); - String expireKey = getExpirationKey(toExpire); - this.redis.boundSetOps(expireKey).remove(session.getId()); - } - - public void onExpirationUpdated(Long originalExpirationTimeInMilli, - ExpiringSession session) { - String keyToExpire = "expires:" + session.getId(); - long toExpire = roundUpToNextMinute(expiresInMillis(session)); - - if (originalExpirationTimeInMilli != null) { - long originalRoundedUp = roundUpToNextMinute(originalExpirationTimeInMilli); - if (toExpire != originalRoundedUp) { - String expireKey = getExpirationKey(originalRoundedUp); - this.redis.boundSetOps(expireKey).remove(keyToExpire); - } - } - - long sessionExpireInSeconds = session.getMaxInactiveIntervalInSeconds(); - String sessionKey = getSessionKey(keyToExpire); - - if (sessionExpireInSeconds < 0) { - this.redis.boundValueOps(sessionKey).append(""); - this.redis.boundValueOps(sessionKey).persist(); - this.redis.boundHashOps(getSessionKey(session.getId())).persist(); - return; - } - - String expireKey = getExpirationKey(toExpire); - BoundSetOperations expireOperations = this.redis - .boundSetOps(expireKey); - expireOperations.add(keyToExpire); - - long fiveMinutesAfterExpires = sessionExpireInSeconds - + TimeUnit.MINUTES.toSeconds(5); - - expireOperations.expire(fiveMinutesAfterExpires, TimeUnit.SECONDS); - if (sessionExpireInSeconds == 0) { - this.redis.delete(sessionKey); - } - else { - this.redis.boundValueOps(sessionKey).append(""); - this.redis.boundValueOps(sessionKey).expire(sessionExpireInSeconds, - TimeUnit.SECONDS); - } - this.redis.boundHashOps(getSessionKey(session.getId())) - .expire(fiveMinutesAfterExpires, TimeUnit.SECONDS); - } - - String getExpirationKey(long expires) { - return this.redisSession.getExpirationsKey(expires); - } - - String getSessionKey(String sessionId) { - return this.redisSession.getSessionKey(sessionId); - } - - public void cleanExpiredSessions() { - long now = System.currentTimeMillis(); - long prevMin = roundDownMinute(now); - - if (logger.isDebugEnabled()) { - logger.debug("Cleaning up sessions expiring at " + new Date(prevMin)); - } - - String expirationKey = getExpirationKey(prevMin); - Set sessionsToExpire = this.redis.boundSetOps(expirationKey).members(); - this.redis.delete(expirationKey); - for (Object session : sessionsToExpire) { - String sessionKey = getSessionKey((String) session); - touch(sessionKey); - } - } - - /** - * By trying to access the session we only trigger a deletion if it the TTL is - * expired. This is done to handle - * https://github.com/spring-projects/spring-session/issues/93 - * - * @param key the key - */ - private void touch(String key) { - this.redis.hasKey(key); - } - - static long expiresInMillis(ExpiringSession session) { - int maxInactiveInSeconds = session.getMaxInactiveIntervalInSeconds(); - long lastAccessedTimeInMillis = session.getLastAccessedTime(); - return lastAccessedTimeInMillis + TimeUnit.SECONDS.toMillis(maxInactiveInSeconds); - } - - static long roundUpToNextMinute(long timeInMs) { - - Calendar date = Calendar.getInstance(); - date.setTimeInMillis(timeInMs); - date.add(Calendar.MINUTE, 1); - date.clear(Calendar.SECOND); - date.clear(Calendar.MILLISECOND); - return date.getTimeInMillis(); - } - - static long roundDownMinute(long timeInMs) { - Calendar date = Calendar.getInstance(); - date.setTimeInMillis(timeInMs); - date.clear(Calendar.SECOND); - date.clear(Calendar.MILLISECOND); - return date.getTimeInMillis(); - } -} diff --git a/spring-session/src/main/java/org/springframework/session/data/redis/config/ConfigureNotifyKeyspaceEventsAction.java b/spring-session/src/main/java/org/springframework/session/data/redis/config/ConfigureNotifyKeyspaceEventsAction.java deleted file mode 100644 index 02a6299..0000000 --- a/spring-session/src/main/java/org/springframework/session/data/redis/config/ConfigureNotifyKeyspaceEventsAction.java +++ /dev/null @@ -1,87 +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.data.redis.config; - -import java.util.List; - -import org.springframework.dao.InvalidDataAccessApiUsageException; -import org.springframework.data.redis.connection.RedisConnection; - -/** - *

- * Ensures that Redis Keyspace events for Generic commands and Expired events are enabled. - * For example, it might set the following: - *

- * - *
- * config set notify-keyspace-events Egx
- * 
- * - *

- * This strategy will not work if the Redis instance has been properly secured. Instead, - * the Redis instance should be configured externally and a Bean of type - * {@link ConfigureRedisAction#NO_OP} should be exposed. - *

- * - * @author Rob Winch - * @since 1.0.1 - */ -public class ConfigureNotifyKeyspaceEventsAction implements ConfigureRedisAction { - - static final String CONFIG_NOTIFY_KEYSPACE_EVENTS = "notify-keyspace-events"; - - /* - * (non-Javadoc) - * - * @see - * org.springframework.session.data.redis.config.ConfigureRedisAction#configure(org. - * springframework.data.redis.connection.RedisConnection) - */ - public void configure(RedisConnection connection) { - String notifyOptions = getNotifyOptions(connection); - String customizedNotifyOptions = notifyOptions; - if (!customizedNotifyOptions.contains("E")) { - customizedNotifyOptions += "E"; - } - boolean A = customizedNotifyOptions.contains("A"); - if (!(A || customizedNotifyOptions.contains("g"))) { - customizedNotifyOptions += "g"; - } - if (!(A || customizedNotifyOptions.contains("x"))) { - customizedNotifyOptions += "x"; - } - if (!notifyOptions.equals(customizedNotifyOptions)) { - connection.setConfig(CONFIG_NOTIFY_KEYSPACE_EVENTS, customizedNotifyOptions); - } - } - - private String getNotifyOptions(RedisConnection connection) { - try { - List config = connection.getConfig(CONFIG_NOTIFY_KEYSPACE_EVENTS); - if (config.size() < 2) { - return ""; - } - return config.get(1); - } - catch (InvalidDataAccessApiUsageException e) { - throw new IllegalStateException( - "Unable to configure Redis to keyspace notifications. See http://docs.spring.io/spring-session/docs/current/reference/html5/#api-redisoperationssessionrepository-sessiondestroyedevent", - e); - } - } - -} diff --git a/spring-session/src/main/java/org/springframework/session/data/redis/config/ConfigureRedisAction.java b/spring-session/src/main/java/org/springframework/session/data/redis/config/ConfigureRedisAction.java deleted file mode 100644 index d896e7d..0000000 --- a/spring-session/src/main/java/org/springframework/session/data/redis/config/ConfigureRedisAction.java +++ /dev/null @@ -1,39 +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.data.redis.config; - -import org.springframework.data.redis.connection.RedisConnection; - -/** - * Allows specifying a strategy for configuring and validating Redis. - * - * @author Rob Winch - * @since 1.0.1 - */ -public interface ConfigureRedisAction { - - void configure(RedisConnection connection); - - /** - * A do nothing implementation of {@link ConfigureRedisAction}. - */ - ConfigureRedisAction NO_OP = new ConfigureRedisAction() { - - public void configure(RedisConnection connection) { - } - }; -} diff --git a/spring-session/src/main/java/org/springframework/session/data/redis/config/annotation/web/http/EnableRedisHttpSession.java b/spring-session/src/main/java/org/springframework/session/data/redis/config/annotation/web/http/EnableRedisHttpSession.java deleted file mode 100644 index df61e2f..0000000 --- a/spring-session/src/main/java/org/springframework/session/data/redis/config/annotation/web/http/EnableRedisHttpSession.java +++ /dev/null @@ -1,96 +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.data.redis.config.annotation.web.http; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; -import org.springframework.data.redis.connection.RedisConnectionFactory; -import org.springframework.session.SessionRepository; -import org.springframework.session.config.annotation.web.http.EnableSpringHttpSession; -import org.springframework.session.data.redis.RedisFlushMode; - -/** - * Add this annotation to an {@code @Configuration} class to expose the - * SessionRepositoryFilter as a bean named "springSessionRepositoryFilter" and backed by - * Redis. In order to leverage the annotation, a single {@link RedisConnectionFactory} - * must be provided. For example:
- * 
- * {@literal @Configuration}
- * {@literal @EnableRedisHttpSession}
- * public class RedisHttpSessionConfig {
- *
- *     {@literal @Bean}
- *     public JedisConnectionFactory connectionFactory() throws Exception {
- *         return new JedisConnectionFactory();
- *     }
- *
- * }
- *  
- * - * More advanced configurations can extend {@link RedisHttpSessionConfiguration} instead. - * - * @author Rob Winch - * @since 1.0 - * @see EnableSpringHttpSession - */ -@Retention(java.lang.annotation.RetentionPolicy.RUNTIME) -@Target({ java.lang.annotation.ElementType.TYPE }) -@Documented -@Import(RedisHttpSessionConfiguration.class) -@Configuration -public @interface EnableRedisHttpSession { - int maxInactiveIntervalInSeconds() default 1800; - - /** - *

- * Defines a unique namespace for keys. The value is used to isolate sessions by - * changing the prefix from "spring:session:" to - * "spring:session:<redisNamespace>:". The default is "" such that all Redis - * keys begin with "spring:session". - *

- * - *

- * For example, if you had an application named "Application A" that needed to keep - * the sessions isolated from "Application B" you could set two different values for - * the applications and they could function within the same Redis instance. - *

- * - * @return the unique namespace for keys - */ - String redisNamespace() default ""; - - /** - *

- * Sets the flush mode for the Redis sessions. The default is ON_SAVE which only - * updates the backing Redis when - * {@link SessionRepository#save(org.springframework.session.Session)} is invoked. In - * a web environment this happens just before the HTTP response is committed. - *

- *

- * Setting the value to IMMEDIATE will ensure that the any updates to the Session are - * immediately written to the Redis instance. - *

- * - * @return the {@link RedisFlushMode} to use - * @since 1.1 - */ - RedisFlushMode redisFlushMode() default RedisFlushMode.ON_SAVE; -} diff --git a/spring-session/src/main/java/org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfiguration.java b/spring-session/src/main/java/org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfiguration.java deleted file mode 100644 index 14e8db9..0000000 --- a/spring-session/src/main/java/org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfiguration.java +++ /dev/null @@ -1,264 +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.data.redis.config.annotation.web.http; - -import java.util.Arrays; -import java.util.Map; -import java.util.concurrent.Executor; - -import org.apache.commons.logging.LogFactory; - -import org.springframework.beans.factory.InitializingBean; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.context.ApplicationEventPublisher; -import org.springframework.context.EmbeddedValueResolverAware; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.ImportAware; -import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; -import org.springframework.core.annotation.AnnotationAttributes; -import org.springframework.core.type.AnnotationMetadata; -import org.springframework.data.redis.connection.RedisConnection; -import org.springframework.data.redis.connection.RedisConnectionFactory; -import org.springframework.data.redis.core.RedisOperations; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.data.redis.listener.PatternTopic; -import org.springframework.data.redis.listener.RedisMessageListenerContainer; -import org.springframework.data.redis.serializer.RedisSerializer; -import org.springframework.data.redis.serializer.StringRedisSerializer; -import org.springframework.scheduling.annotation.EnableScheduling; -import org.springframework.session.config.annotation.web.http.SpringHttpSessionConfiguration; -import org.springframework.session.data.redis.RedisFlushMode; -import org.springframework.session.data.redis.RedisOperationsSessionRepository; -import org.springframework.session.data.redis.config.ConfigureNotifyKeyspaceEventsAction; -import org.springframework.session.data.redis.config.ConfigureRedisAction; -import org.springframework.session.web.http.SessionRepositoryFilter; -import org.springframework.util.Assert; -import org.springframework.util.StringUtils; -import org.springframework.util.StringValueResolver; - -/** - * Exposes the {@link SessionRepositoryFilter} as a bean named - * "springSessionRepositoryFilter". In order to use this a single - * {@link RedisConnectionFactory} must be exposed as a Bean. - * - * @author Rob Winch - * @author Eddú Meléndez - * @see EnableRedisHttpSession - * @since 1.0 - */ -@Configuration -@EnableScheduling -public class RedisHttpSessionConfiguration extends SpringHttpSessionConfiguration - implements EmbeddedValueResolverAware, ImportAware { - - private Integer maxInactiveIntervalInSeconds = 1800; - - private ConfigureRedisAction configureRedisAction = new ConfigureNotifyKeyspaceEventsAction(); - - private String redisNamespace = ""; - - private RedisFlushMode redisFlushMode = RedisFlushMode.ON_SAVE; - - private RedisSerializer defaultRedisSerializer; - - private Executor redisTaskExecutor; - - private Executor redisSubscriptionExecutor; - - private StringValueResolver embeddedValueResolver; - - @Bean - public RedisMessageListenerContainer redisMessageListenerContainer( - RedisConnectionFactory connectionFactory, - RedisOperationsSessionRepository messageListener) { - - RedisMessageListenerContainer container = new RedisMessageListenerContainer(); - container.setConnectionFactory(connectionFactory); - if (this.redisTaskExecutor != null) { - container.setTaskExecutor(this.redisTaskExecutor); - } - if (this.redisSubscriptionExecutor != null) { - container.setSubscriptionExecutor(this.redisSubscriptionExecutor); - } - container.addMessageListener(messageListener, - Arrays.asList(new PatternTopic("__keyevent@*:del"), - new PatternTopic("__keyevent@*:expired"))); - container.addMessageListener(messageListener, Arrays.asList(new PatternTopic( - messageListener.getSessionCreatedChannelPrefix() + "*"))); - return container; - } - - @Bean - public RedisTemplate sessionRedisTemplate( - RedisConnectionFactory connectionFactory) { - RedisTemplate template = new RedisTemplate(); - template.setKeySerializer(new StringRedisSerializer()); - template.setHashKeySerializer(new StringRedisSerializer()); - if (this.defaultRedisSerializer != null) { - template.setDefaultSerializer(this.defaultRedisSerializer); - } - template.setConnectionFactory(connectionFactory); - return template; - } - - @Bean - public RedisOperationsSessionRepository sessionRepository( - @Qualifier("sessionRedisTemplate") RedisOperations sessionRedisTemplate, - ApplicationEventPublisher applicationEventPublisher) { - RedisOperationsSessionRepository sessionRepository = new RedisOperationsSessionRepository( - sessionRedisTemplate); - sessionRepository.setApplicationEventPublisher(applicationEventPublisher); - sessionRepository - .setDefaultMaxInactiveInterval(this.maxInactiveIntervalInSeconds); - if (this.defaultRedisSerializer != null) { - sessionRepository.setDefaultSerializer(this.defaultRedisSerializer); - } - - String redisNamespace = getRedisNamespace(); - if (StringUtils.hasText(redisNamespace)) { - sessionRepository.setRedisKeyNamespace(redisNamespace); - } - - sessionRepository.setRedisFlushMode(this.redisFlushMode); - return sessionRepository; - } - - public void setMaxInactiveIntervalInSeconds(int maxInactiveIntervalInSeconds) { - this.maxInactiveIntervalInSeconds = maxInactiveIntervalInSeconds; - } - - public void setRedisNamespace(String namespace) { - this.redisNamespace = namespace; - } - - public void setRedisFlushMode(RedisFlushMode redisFlushMode) { - Assert.notNull(redisFlushMode, "redisFlushMode cannot be null"); - this.redisFlushMode = redisFlushMode; - } - - private String getRedisNamespace() { - if (StringUtils.hasText(this.redisNamespace)) { - return this.redisNamespace; - } - return System.getProperty("spring.session.redis.namespace", ""); - } - - public void setImportMetadata(AnnotationMetadata importMetadata) { - - Map enableAttrMap = importMetadata - .getAnnotationAttributes(EnableRedisHttpSession.class.getName()); - AnnotationAttributes enableAttrs = AnnotationAttributes.fromMap(enableAttrMap); - this.maxInactiveIntervalInSeconds = enableAttrs - .getNumber("maxInactiveIntervalInSeconds"); - String redisNamespaceValue = enableAttrs.getString("redisNamespace"); - if (StringUtils.hasText(redisNamespaceValue)) { - this.redisNamespace = this.embeddedValueResolver.resolveStringValue(redisNamespaceValue); - } - this.redisFlushMode = enableAttrs.getEnum("redisFlushMode"); - } - - @Bean - public InitializingBean enableRedisKeyspaceNotificationsInitializer( - RedisConnectionFactory connectionFactory) { - return new EnableRedisKeyspaceNotificationsInitializer(connectionFactory, - this.configureRedisAction); - } - - /** - * Sets the action to perform for configuring Redis. - * - * @param configureRedisAction the configureRedis to set. The default is - * {@link ConfigureNotifyKeyspaceEventsAction}. - */ - @Autowired(required = false) - public void setConfigureRedisAction(ConfigureRedisAction configureRedisAction) { - this.configureRedisAction = configureRedisAction; - } - - @Autowired(required = false) - @Qualifier("springSessionDefaultRedisSerializer") - public void setDefaultRedisSerializer( - RedisSerializer defaultRedisSerializer) { - this.defaultRedisSerializer = defaultRedisSerializer; - } - - @Autowired(required = false) - @Qualifier("springSessionRedisTaskExecutor") - public void setRedisTaskExecutor(Executor redisTaskExecutor) { - this.redisTaskExecutor = redisTaskExecutor; - } - - @Autowired(required = false) - @Qualifier("springSessionRedisSubscriptionExecutor") - public void setRedisSubscriptionExecutor(Executor redisSubscriptionExecutor) { - this.redisSubscriptionExecutor = redisSubscriptionExecutor; - } - - public void setEmbeddedValueResolver(StringValueResolver resolver) { - this.embeddedValueResolver = resolver; - } - - /** - * Property placeholder to process the @Scheduled annotation. - * @return the {@link PropertySourcesPlaceholderConfigurer} to use - */ - @Bean - public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() { - return new PropertySourcesPlaceholderConfigurer(); - } - - /** - * Ensures that Redis is configured to send keyspace notifications. This is important - * to ensure that expiration and deletion of sessions trigger SessionDestroyedEvents. - * Without the SessionDestroyedEvent resources may not get cleaned up properly. For - * example, the mapping of the Session to WebSocket connections may not get cleaned - * up. - */ - static class EnableRedisKeyspaceNotificationsInitializer implements InitializingBean { - private final RedisConnectionFactory connectionFactory; - - private ConfigureRedisAction configure; - - EnableRedisKeyspaceNotificationsInitializer( - RedisConnectionFactory connectionFactory, - ConfigureRedisAction configure) { - this.connectionFactory = connectionFactory; - this.configure = configure; - } - - public void afterPropertiesSet() throws Exception { - if (this.configure == ConfigureRedisAction.NO_OP) { - return; - } - RedisConnection connection = this.connectionFactory.getConnection(); - try { - this.configure.configure(connection); - } - finally { - try { - connection.close(); - } - catch (Exception e) { - LogFactory.getLog(getClass()).error("Error closing RedisConnection", e); - } - } - } - } - -} diff --git a/spring-session/src/main/java/org/springframework/session/events/AbstractSessionEvent.java b/spring-session/src/main/java/org/springframework/session/events/AbstractSessionEvent.java deleted file mode 100644 index a48048a..0000000 --- a/spring-session/src/main/java/org/springframework/session/events/AbstractSessionEvent.java +++ /dev/null @@ -1,65 +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.events; - -import org.springframework.context.ApplicationEvent; -import org.springframework.session.Session; -import org.springframework.session.SessionRepository; - -/** - * For {@link SessionRepository} implementations that support it, this event is fired when - * a {@link Session} is updated. - * - * @author Rob Winch - * @since 1.1 - */ -@SuppressWarnings("serial") -public abstract class AbstractSessionEvent extends ApplicationEvent { - private final String sessionId; - - private final Session session; - - protected AbstractSessionEvent(Object source, String sessionId) { - super(source); - this.sessionId = sessionId; - this.session = null; - } - - AbstractSessionEvent(Object source, Session session) { - super(source); - this.session = session; - this.sessionId = session.getId(); - } - - /** - * Gets the {@link Session} that was destroyed. For some {@link SessionRepository} - * implementations it may not be possible to get the original session in which case - * this may be null. - * - * @param The type of Session - * @return the expired {@link Session} or null if the data store does not support - * obtaining it - */ - @SuppressWarnings("unchecked") - public S getSession() { - return (S) this.session; - } - - public String getSessionId() { - return this.sessionId; - } -} diff --git a/spring-session/src/main/java/org/springframework/session/events/SessionCreatedEvent.java b/spring-session/src/main/java/org/springframework/session/events/SessionCreatedEvent.java deleted file mode 100644 index a5ba859..0000000 --- a/spring-session/src/main/java/org/springframework/session/events/SessionCreatedEvent.java +++ /dev/null @@ -1,46 +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.events; - -import org.springframework.session.Session; -import org.springframework.session.SessionRepository; - -/** - * For {@link SessionRepository} implementations that support it, this event is fired when - * a {@link Session} is created. - * - * @author Rob Winch - * @since 1.0 - * - */ -@SuppressWarnings("serial") -public class SessionCreatedEvent extends AbstractSessionEvent { - - public SessionCreatedEvent(Object source, String sessionId) { - super(source, sessionId); - } - - /** - * Create a new {@link SessionCreatedEvent}. - * @param source The Source of the SessionCreatedEvent - * @param session the Session that was created - */ - public SessionCreatedEvent(Object source, Session session) { - super(source, session); - } - -} diff --git a/spring-session/src/main/java/org/springframework/session/events/SessionDeletedEvent.java b/spring-session/src/main/java/org/springframework/session/events/SessionDeletedEvent.java deleted file mode 100644 index 484a8bd..0000000 --- a/spring-session/src/main/java/org/springframework/session/events/SessionDeletedEvent.java +++ /dev/null @@ -1,41 +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.events; - -import org.springframework.session.Session; -import org.springframework.session.SessionRepository; - -/** - * For {@link SessionRepository} implementations that support it, this event is fired when - * a {@link Session} is destroyed via deletion. - * - * @author Mark Anderson - * @author Rob Winch - * @since 1.1 - * - */ -@SuppressWarnings("serial") -public class SessionDeletedEvent extends SessionDestroyedEvent { - - public SessionDeletedEvent(Object source, String sessionId) { - super(source, sessionId); - } - - public SessionDeletedEvent(Object source, Session session) { - super(source, session); - } -} diff --git a/spring-session/src/main/java/org/springframework/session/events/SessionDestroyedEvent.java b/spring-session/src/main/java/org/springframework/session/events/SessionDestroyedEvent.java deleted file mode 100644 index 9eacbe4..0000000 --- a/spring-session/src/main/java/org/springframework/session/events/SessionDestroyedEvent.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 org.springframework.session.events; - -import org.springframework.session.Session; - -/** - * Base class for events fired when a {@link Session} is destroyed explicitly. - * - * @author Rob Winch - * @since 1.0 - * - */ -@SuppressWarnings("serial") -public class SessionDestroyedEvent extends AbstractSessionEvent { - - public SessionDestroyedEvent(Object source, String sessionId) { - super(source, sessionId); - } - - /** - * Create a new {@link SessionDestroyedEvent}. - * @param source The Source of the SessionDestoryedEvent - * @param session the Session that was created - */ - public SessionDestroyedEvent(Object source, Session session) { - super(source, session); - } -} diff --git a/spring-session/src/main/java/org/springframework/session/events/SessionExpiredEvent.java b/spring-session/src/main/java/org/springframework/session/events/SessionExpiredEvent.java deleted file mode 100644 index f2efeac..0000000 --- a/spring-session/src/main/java/org/springframework/session/events/SessionExpiredEvent.java +++ /dev/null @@ -1,41 +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.events; - -import org.springframework.session.Session; -import org.springframework.session.SessionRepository; - -/** - * For {@link SessionRepository} implementations that support it, this event is fired when - * a {@link Session} is destroyed via expiration. - * - * @author Mark Anderson - * @author Rob Winch - * @since 1.1 - * - */ -@SuppressWarnings("serial") -public class SessionExpiredEvent extends SessionDestroyedEvent { - - public SessionExpiredEvent(Object source, String sessionId) { - super(source, sessionId); - } - - public SessionExpiredEvent(Object source, Session session) { - super(source, session); - } -} diff --git a/spring-session/src/main/java/org/springframework/session/hazelcast/HazelcastFlushMode.java b/spring-session/src/main/java/org/springframework/session/hazelcast/HazelcastFlushMode.java deleted file mode 100644 index e632e39..0000000 --- a/spring-session/src/main/java/org/springframework/session/hazelcast/HazelcastFlushMode.java +++ /dev/null @@ -1,44 +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.hazelcast; - -import org.springframework.session.SessionRepository; - -/** - * Specifies when to write to the backing Hazelcast instance. - * - * @author Aleksandar Stojsavljevic - * @since 1.3.0 - */ -public enum HazelcastFlushMode { - - /** - * Only writes to Hazelcast when - * {@link SessionRepository#save(org.springframework.session.Session)} is invoked. In - * a web environment this is typically done as soon as the HTTP response is committed. - */ - ON_SAVE, - - /** - * Writes to Hazelcast as soon as possible. For example - * {@link SessionRepository#createSession()} will write the session to Hazelcast. - * Another example is that setting an attribute on the session will also write to - * Hazelcast immediately. - */ - IMMEDIATE - -} diff --git a/spring-session/src/main/java/org/springframework/session/hazelcast/HazelcastSessionRepository.java b/spring-session/src/main/java/org/springframework/session/hazelcast/HazelcastSessionRepository.java deleted file mode 100644 index 2c55179..0000000 --- a/spring-session/src/main/java/org/springframework/session/hazelcast/HazelcastSessionRepository.java +++ /dev/null @@ -1,367 +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.hazelcast; - -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.TimeUnit; - -import javax.annotation.PostConstruct; -import javax.annotation.PreDestroy; - -import com.hazelcast.core.EntryEvent; -import com.hazelcast.core.IMap; -import com.hazelcast.map.listener.EntryAddedListener; -import com.hazelcast.map.listener.EntryEvictedListener; -import com.hazelcast.map.listener.EntryRemovedListener; -import com.hazelcast.query.Predicates; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.context.ApplicationEvent; -import org.springframework.context.ApplicationEventPublisher; -import org.springframework.session.ExpiringSession; -import org.springframework.session.FindByIndexNameSessionRepository; -import org.springframework.session.MapSession; -import org.springframework.session.Session; -import org.springframework.session.events.AbstractSessionEvent; -import org.springframework.session.events.SessionCreatedEvent; -import org.springframework.session.events.SessionDeletedEvent; -import org.springframework.session.events.SessionExpiredEvent; -import org.springframework.util.Assert; - -/** - * A {@link org.springframework.session.SessionRepository} implementation that stores - * sessions in Hazelcast's distributed {@link IMap}. - * - *

- * An example of how to create a new instance can be seen below: - * - *

- * Config config = new Config();
- *
- * // ... configure Hazelcast ...
- *
- * HazelcastInstance hazelcastInstance = Hazelcast.newHazelcastInstance(config);
- *
- * IMap{@code } sessions = hazelcastInstance
- *         .getMap("spring:session:sessions");
- *
- * HazelcastSessionRepository sessionRepository =
- *         new HazelcastSessionRepository(sessions);
- * 
- * - * In order to support finding sessions by principal name using - * {@link #findByIndexNameAndIndexValue(String, String)} method, custom configuration of - * {@code IMap} supplied to this implementation is required. - * - * The following snippet demonstrates how to define required configuration using - * programmatic Hazelcast Configuration: - * - *
- * MapAttributeConfig attributeConfig = new MapAttributeConfig()
- *         .setName(HazelcastSessionRepository.PRINCIPAL_NAME_ATTRIBUTE)
- *         .setExtractor(PrincipalNameExtractor.class.getName());
- *
- * Config config = new Config();
- *
- * config.getMapConfig("spring:session:sessions")
- *         .addMapAttributeConfig(attributeConfig)
- *         .addMapIndexConfig(new MapIndexConfig(
- *                 HazelcastSessionRepository.PRINCIPAL_NAME_ATTRIBUTE, false));
- *
- * Hazelcast.newHazelcastInstance(config);
- * 
- * - * This implementation listens for events on the Hazelcast-backed SessionRepository and - * translates those events into the corresponding Spring Session events. Publish the - * Spring Session events with the given {@link ApplicationEventPublisher}. - * - *
    - *
  • entryAdded - {@link SessionCreatedEvent}
  • - *
  • entryEvicted - {@link SessionExpiredEvent}
  • - *
  • entryRemoved - {@link SessionDeletedEvent}
  • - *
- * - * @author Vedran Pavic - * @author Tommy Ludwig - * @author Mark Anderson - * @author Aleksandar Stojsavljevic - * @since 1.3.0 - */ -public class HazelcastSessionRepository implements - FindByIndexNameSessionRepository, - EntryAddedListener, - EntryEvictedListener, - EntryRemovedListener { - - /** - * The principal name custom attribute name. - */ - public static final String PRINCIPAL_NAME_ATTRIBUTE = "principalName"; - - private static final Log logger = LogFactory.getLog(HazelcastSessionRepository.class); - - private final IMap sessions; - - private HazelcastFlushMode hazelcastFlushMode = HazelcastFlushMode.ON_SAVE; - - private ApplicationEventPublisher eventPublisher = new ApplicationEventPublisher() { - - public void publishEvent(ApplicationEvent event) { - } - - public void publishEvent(Object event) { - } - - }; - - /** - * If non-null, this value is used to override - * {@link MapSession#setMaxInactiveIntervalInSeconds(int)}. - */ - private Integer defaultMaxInactiveInterval; - - private String sessionListenerId; - - public HazelcastSessionRepository(IMap sessions) { - Assert.notNull(sessions, "Sessions IMap must not be null"); - this.sessions = sessions; - } - - @PostConstruct - private void init() { - this.sessionListenerId = this.sessions.addEntryListener(this, true); - } - - @PreDestroy - private void close() { - this.sessions.removeEntryListener(this.sessionListenerId); - } - - /** - * Sets the {@link ApplicationEventPublisher} that is used to publish - * {@link AbstractSessionEvent session events}. The default is to not publish session - * events. - * - * @param applicationEventPublisher the {@link ApplicationEventPublisher} that is used - * to publish session events. Cannot be null. - */ - public void setApplicationEventPublisher( - ApplicationEventPublisher applicationEventPublisher) { - Assert.notNull(applicationEventPublisher, - "ApplicationEventPublisher cannot be null"); - this.eventPublisher = applicationEventPublisher; - } - - /** - * Set the maximum inactive interval in seconds between requests before newly created - * sessions will be invalidated. A negative time indicates that the session will never - * timeout. The default is 1800 (30 minutes). - * @param defaultMaxInactiveInterval the maximum inactive interval in seconds - */ - public void setDefaultMaxInactiveInterval(Integer defaultMaxInactiveInterval) { - this.defaultMaxInactiveInterval = defaultMaxInactiveInterval; - } - - /** - * Sets the Hazelcast flush mode. Default flush mode is - * {@link HazelcastFlushMode#ON_SAVE}. - * @param hazelcastFlushMode the new Hazelcast flush mode - */ - public void setHazelcastFlushMode(HazelcastFlushMode hazelcastFlushMode) { - Assert.notNull(hazelcastFlushMode, "HazelcastFlushMode cannot be null"); - this.hazelcastFlushMode = hazelcastFlushMode; - } - - public HazelcastSession createSession() { - HazelcastSession result = new HazelcastSession(); - if (this.defaultMaxInactiveInterval != null) { - result.setMaxInactiveIntervalInSeconds(this.defaultMaxInactiveInterval); - } - return result; - } - - public void save(HazelcastSession session) { - if (session.isChanged()) { - this.sessions.put(session.getId(), session.getDelegate(), - session.getMaxInactiveIntervalInSeconds(), TimeUnit.SECONDS); - session.markUnchanged(); - } - } - - public HazelcastSession getSession(String id) { - MapSession saved = this.sessions.get(id); - if (saved == null) { - return null; - } - if (saved.isExpired()) { - delete(saved.getId()); - return null; - } - return new HazelcastSession(saved); - } - - public void delete(String id) { - this.sessions.remove(id); - } - - public Map findByIndexNameAndIndexValue( - String indexName, String indexValue) { - if (!PRINCIPAL_NAME_INDEX_NAME.equals(indexName)) { - return Collections.emptyMap(); - } - Collection sessions = this.sessions.values( - Predicates.equal(PRINCIPAL_NAME_ATTRIBUTE, indexValue)); - Map sessionMap = new HashMap( - sessions.size()); - for (MapSession session : sessions) { - sessionMap.put(session.getId(), new HazelcastSession(session)); - } - return sessionMap; - } - - public void entryAdded(EntryEvent event) { - if (logger.isDebugEnabled()) { - logger.debug("Session created with id: " + event.getValue().getId()); - } - this.eventPublisher.publishEvent(new SessionCreatedEvent(this, event.getValue())); - } - - public void entryEvicted(EntryEvent event) { - if (logger.isDebugEnabled()) { - logger.debug("Session expired with id: " + event.getOldValue().getId()); - } - this.eventPublisher - .publishEvent(new SessionExpiredEvent(this, event.getOldValue())); - } - - public void entryRemoved(EntryEvent event) { - if (logger.isDebugEnabled()) { - logger.debug("Session deleted with id: " + event.getOldValue().getId()); - } - this.eventPublisher - .publishEvent(new SessionDeletedEvent(this, event.getOldValue())); - } - - /** - * A custom implementation of {@link Session} that uses a {@link MapSession} as the - * basis for its mapping. It keeps track if changes have been made since last save. - * - * @author Aleksandar Stojsavljevic - */ - final class HazelcastSession implements ExpiringSession { - - private final MapSession delegate; - private boolean changed; - - /** - * Creates a new instance ensuring to mark all of the new attributes to be - * persisted in the next save operation. - */ - HazelcastSession() { - this(new MapSession()); - this.changed = true; - flushImmediateIfNecessary(); - } - - /** - * Creates a new instance from the provided {@link MapSession}. - * @param cached the {@link MapSession} that represents the persisted session that - * was retrieved. Cannot be {@code null}. - */ - HazelcastSession(MapSession cached) { - Assert.notNull(cached, "MapSession cannot be null"); - this.delegate = cached; - } - - public void setLastAccessedTime(long lastAccessedTime) { - this.delegate.setLastAccessedTime(lastAccessedTime); - this.changed = true; - flushImmediateIfNecessary(); - } - - public boolean isExpired() { - return this.delegate.isExpired(); - } - - public long getCreationTime() { - return this.delegate.getCreationTime(); - } - - public String getId() { - return this.delegate.getId(); - } - - public long getLastAccessedTime() { - return this.delegate.getLastAccessedTime(); - } - - public void setMaxInactiveIntervalInSeconds(int interval) { - this.delegate.setMaxInactiveIntervalInSeconds(interval); - this.changed = true; - flushImmediateIfNecessary(); - } - - public int getMaxInactiveIntervalInSeconds() { - return this.delegate.getMaxInactiveIntervalInSeconds(); - } - - public T getAttribute(String attributeName) { - return this.delegate.getAttribute(attributeName); - } - - public Set getAttributeNames() { - return this.delegate.getAttributeNames(); - } - - public void setAttribute(String attributeName, Object attributeValue) { - this.delegate.setAttribute(attributeName, attributeValue); - this.changed = true; - flushImmediateIfNecessary(); - } - - public void removeAttribute(String attributeName) { - this.delegate.removeAttribute(attributeName); - this.changed = true; - flushImmediateIfNecessary(); - } - - boolean isChanged() { - return this.changed; - } - - void markUnchanged() { - this.changed = false; - } - - MapSession getDelegate() { - return this.delegate; - } - - private void flushImmediateIfNecessary() { - if (HazelcastSessionRepository.this.hazelcastFlushMode == HazelcastFlushMode.IMMEDIATE) { - HazelcastSessionRepository.this.save(this); - } - } - - } - -} diff --git a/spring-session/src/main/java/org/springframework/session/hazelcast/PrincipalNameExtractor.java b/spring-session/src/main/java/org/springframework/session/hazelcast/PrincipalNameExtractor.java deleted file mode 100644 index d63966b..0000000 --- a/spring-session/src/main/java/org/springframework/session/hazelcast/PrincipalNameExtractor.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.hazelcast; - -import com.hazelcast.query.extractor.ValueCollector; -import com.hazelcast.query.extractor.ValueExtractor; - -import org.springframework.expression.Expression; -import org.springframework.expression.spel.standard.SpelExpressionParser; -import org.springframework.session.FindByIndexNameSessionRepository; -import org.springframework.session.MapSession; -import org.springframework.session.Session; - -/** - * Hazelcast {@link ValueExtractor} responsible for extracting principal name from the - * {@link MapSession}. - * - * @author Vedran Pavic - * @since 1.3.0 - */ -public class PrincipalNameExtractor extends ValueExtractor { - - private static final PrincipalNameResolver PRINCIPAL_NAME_RESOLVER = - new PrincipalNameResolver(); - - @SuppressWarnings("unchecked") - public void extract(MapSession target, String argument, - ValueCollector collector) { - String principalName = PRINCIPAL_NAME_RESOLVER.resolvePrincipal(target); - if (principalName != null) { - collector.addObject(principalName); - } - } - - /** - * Resolves the Spring Security principal name. - */ - static class PrincipalNameResolver { - - private static final String SPRING_SECURITY_CONTEXT = "SPRING_SECURITY_CONTEXT"; - - private SpelExpressionParser parser = new SpelExpressionParser(); - - public String resolvePrincipal(Session session) { - String principalName = session.getAttribute( - FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME); - if (principalName != null) { - return principalName; - } - Object authentication = session.getAttribute(SPRING_SECURITY_CONTEXT); - if (authentication != null) { - Expression expression = this.parser - .parseExpression("authentication?.name"); - return expression.getValue(authentication, String.class); - } - return null; - } - - } - -} diff --git a/spring-session/src/main/java/org/springframework/session/hazelcast/config/annotation/web/http/EnableHazelcastHttpSession.java b/spring-session/src/main/java/org/springframework/session/hazelcast/config/annotation/web/http/EnableHazelcastHttpSession.java deleted file mode 100644 index 14db366..0000000 --- a/spring-session/src/main/java/org/springframework/session/hazelcast/config/annotation/web/http/EnableHazelcastHttpSession.java +++ /dev/null @@ -1,92 +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.hazelcast.config.annotation.web.http; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; -import org.springframework.session.MapSession; -import org.springframework.session.SessionRepository; -import org.springframework.session.config.annotation.web.http.EnableSpringHttpSession; -import org.springframework.session.hazelcast.HazelcastFlushMode; - -/** - * Add this annotation to a {@code @Configuration} class to expose the - * SessionRepositoryFilter as a bean named "springSessionRepositoryFilter" and backed by - * Hazelcast. In order to leverage the annotation, a single HazelcastInstance must be - * provided. For example:
- * 
- * {@literal @Configuration}
- * {@literal @EnableHazelcastHttpSession}
- * public class HazelcastHttpSessionConfig {
- *
- *     {@literal @Bean}
- *     public HazelcastInstance embeddedHazelcast() {
- *         Config hazelcastConfig = new Config();
- *         return Hazelcast.newHazelcastInstance(hazelcastConfig);
- *     }
- *
- * }
- *  
- * - * More advanced configurations can extend {@link HazelcastHttpSessionConfiguration} - * instead. - * - * @author Tommy Ludwig - * @author Aleksandar Stojsavljevic - * @since 1.1 - * @see EnableSpringHttpSession - */ -@Retention(java.lang.annotation.RetentionPolicy.RUNTIME) -@Target({ java.lang.annotation.ElementType.TYPE }) -@Documented -@Import(HazelcastHttpSessionConfiguration.class) -@Configuration -public @interface EnableHazelcastHttpSession { - - /** - * This is the session timeout in seconds. By default, it is set to 1800 seconds (30 - * minutes). This should be a non-negative integer. - * - * @return the seconds a session can be inactive before expiring - */ - int maxInactiveIntervalInSeconds() default MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS; - - /** - * This is the name of the Map that will be used in Hazelcast to store the session - * data. Default is {@link HazelcastHttpSessionConfiguration#DEFAULT_SESSION_MAP_NAME}. - * @return the name of the Map to store the sessions in Hazelcast - */ - String sessionMapName() default HazelcastHttpSessionConfiguration.DEFAULT_SESSION_MAP_NAME; - - /** - * Flush mode for the Hazelcast sessions. The default is {@code ON_SAVE} which only - * updates the backing Hazelcast when - * {@link SessionRepository#save(org.springframework.session.Session)} is invoked. In - * a web environment this happens just before the HTTP response is committed. - *

- * Setting the value to {@code IMMEDIATE} will ensure that the any updates to the - * Session are immediately written to the Hazelcast instance. - * @return the {@link HazelcastFlushMode} to use - * @since 1.3.0 - */ - HazelcastFlushMode hazelcastFlushMode() default HazelcastFlushMode.ON_SAVE; - -} diff --git a/spring-session/src/main/java/org/springframework/session/hazelcast/config/annotation/web/http/HazelcastHttpSessionConfiguration.java b/spring-session/src/main/java/org/springframework/session/hazelcast/config/annotation/web/http/HazelcastHttpSessionConfiguration.java deleted file mode 100644 index 0ce637d..0000000 --- a/spring-session/src/main/java/org/springframework/session/hazelcast/config/annotation/web/http/HazelcastHttpSessionConfiguration.java +++ /dev/null @@ -1,96 +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.hazelcast.config.annotation.web.http; - -import java.util.Map; - -import com.hazelcast.core.HazelcastInstance; -import com.hazelcast.core.IMap; - -import org.springframework.context.ApplicationEventPublisher; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.ImportAware; -import org.springframework.core.annotation.AnnotationAttributes; -import org.springframework.core.type.AnnotationMetadata; -import org.springframework.session.MapSession; -import org.springframework.session.config.annotation.web.http.SpringHttpSessionConfiguration; -import org.springframework.session.hazelcast.HazelcastFlushMode; -import org.springframework.session.hazelcast.HazelcastSessionRepository; -import org.springframework.session.web.http.SessionRepositoryFilter; - -/** - * Exposes the {@link SessionRepositoryFilter} as a bean named - * "springSessionRepositoryFilter". In order to use this a single - * {@link HazelcastInstance} must be exposed as a Bean. - * - * @author Tommy Ludwig - * @author Vedran Pavic - * @since 1.1 - * @see EnableHazelcastHttpSession - */ -@Configuration -public class HazelcastHttpSessionConfiguration extends SpringHttpSessionConfiguration - implements ImportAware { - - static final String DEFAULT_SESSION_MAP_NAME = "spring:session:sessions"; - - private Integer maxInactiveIntervalInSeconds; - - private String sessionMapName = DEFAULT_SESSION_MAP_NAME; - - private HazelcastFlushMode hazelcastFlushMode = HazelcastFlushMode.ON_SAVE; - - @Bean - public HazelcastSessionRepository sessionRepository( - HazelcastInstance hazelcastInstance, - ApplicationEventPublisher eventPublisher) { - IMap sessions = hazelcastInstance.getMap( - this.sessionMapName); - HazelcastSessionRepository sessionRepository = new HazelcastSessionRepository( - sessions); - sessionRepository.setApplicationEventPublisher(eventPublisher); - sessionRepository.setDefaultMaxInactiveInterval( - this.maxInactiveIntervalInSeconds); - sessionRepository.setHazelcastFlushMode(this.hazelcastFlushMode); - return sessionRepository; - } - - public void setImportMetadata(AnnotationMetadata importMetadata) { - Map enableAttrMap = importMetadata - .getAnnotationAttributes(EnableHazelcastHttpSession.class.getName()); - AnnotationAttributes enableAttrs = AnnotationAttributes.fromMap(enableAttrMap); - setMaxInactiveIntervalInSeconds( - (Integer) enableAttrs.getNumber("maxInactiveIntervalInSeconds")); - setSessionMapName(enableAttrs.getString("sessionMapName")); - setHazelcastFlushMode( - (HazelcastFlushMode) enableAttrs.getEnum("hazelcastFlushMode")); - } - - public void setMaxInactiveIntervalInSeconds(int maxInactiveIntervalInSeconds) { - this.maxInactiveIntervalInSeconds = maxInactiveIntervalInSeconds; - } - - public void setSessionMapName(String sessionMapName) { - this.sessionMapName = sessionMapName; - } - - public void setHazelcastFlushMode(HazelcastFlushMode hazelcastFlushMode) { - this.hazelcastFlushMode = hazelcastFlushMode; - } - -} diff --git a/spring-session/src/main/java/org/springframework/session/jdbc/JdbcOperationsSessionRepository.java b/spring-session/src/main/java/org/springframework/session/jdbc/JdbcOperationsSessionRepository.java deleted file mode 100644 index 28b2e8b..0000000 --- a/spring-session/src/main/java/org/springframework/session/jdbc/JdbcOperationsSessionRepository.java +++ /dev/null @@ -1,798 +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.jdbc; - -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import javax.sql.DataSource; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.core.convert.ConversionService; -import org.springframework.core.convert.TypeDescriptor; -import org.springframework.core.convert.support.GenericConversionService; -import org.springframework.core.serializer.support.DeserializingConverter; -import org.springframework.core.serializer.support.SerializingConverter; -import org.springframework.dao.DataAccessException; -import org.springframework.expression.Expression; -import org.springframework.expression.spel.standard.SpelExpressionParser; -import org.springframework.jdbc.core.BatchPreparedStatementSetter; -import org.springframework.jdbc.core.JdbcOperations; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.jdbc.core.PreparedStatementSetter; -import org.springframework.jdbc.core.ResultSetExtractor; -import org.springframework.jdbc.support.lob.DefaultLobHandler; -import org.springframework.jdbc.support.lob.LobHandler; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.session.ExpiringSession; -import org.springframework.session.FindByIndexNameSessionRepository; -import org.springframework.session.MapSession; -import org.springframework.session.Session; -import org.springframework.transaction.PlatformTransactionManager; -import org.springframework.transaction.TransactionDefinition; -import org.springframework.transaction.TransactionStatus; -import org.springframework.transaction.support.TransactionCallback; -import org.springframework.transaction.support.TransactionCallbackWithoutResult; -import org.springframework.transaction.support.TransactionOperations; -import org.springframework.transaction.support.TransactionTemplate; -import org.springframework.util.Assert; -import org.springframework.util.StringUtils; - -/** - * A {@link org.springframework.session.SessionRepository} implementation that uses - * Spring's {@link JdbcOperations} to store sessions in a relational database. This - * implementation does not support publishing of session events. - *

- * An example of how to create a new instance can be seen below: - * - *

- * JdbcTemplate jdbcTemplate = new JdbcTemplate();
- *
- * // ... configure jdbcTemplate ...
- *
- * PlatformTransactionManager transactionManager = new DataSourceTransactionManager();
- *
- * // ... configure transactionManager ...
- *
- * JdbcOperationsSessionRepository sessionRepository =
- *         new JdbcOperationsSessionRepository(jdbcTemplate, transactionManager);
- * 
- * - * For additional information on how to create and configure {@link JdbcTemplate} and - * {@link PlatformTransactionManager}, refer to the - * - * Spring Framework Reference Documentation. - *

- * By default, this implementation uses SPRING_SESSION and - * SPRING_SESSION_ATTRIBUTES tables to store sessions. Note that the table - * name can be customized using the {@link #setTableName(String)} method. In that case the - * table used to store attributes will be named using the provided table name, suffixed - * with _ATTRIBUTES. - * - * Depending on your database, the table definition can be described as below: - * - *

- * CREATE TABLE SPRING_SESSION (
- *   SESSION_ID CHAR(36),
- *   CREATION_TIME BIGINT NOT NULL,
- *   LAST_ACCESS_TIME BIGINT NOT NULL,
- *   MAX_INACTIVE_INTERVAL INT NOT NULL,
- *   PRINCIPAL_NAME VARCHAR(100),
- *   CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (SESSION_ID)
- * );
- *
- * CREATE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (LAST_ACCESS_TIME);
- *
- * CREATE TABLE SPRING_SESSION_ATTRIBUTES (
- *  SESSION_ID CHAR(36),
- *  ATTRIBUTE_NAME VARCHAR(200),
- *  ATTRIBUTE_BYTES BYTEA,
- *  CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_ID, ATTRIBUTE_NAME),
- *  CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_ID) REFERENCES SPRING_SESSION(SESSION_ID) ON DELETE CASCADE
- * );
- *
- * CREATE INDEX SPRING_SESSION_ATTRIBUTES_IX1 ON SPRING_SESSION_ATTRIBUTES (SESSION_ID);
- * 
- * - * Due to the differences between the various database vendors, especially when it comes - * to storing binary data, make sure to use SQL script specific to your database. Scripts - * for most major database vendors are packaged as - * org/springframework/session/jdbc/schema-*.sql, where * is the - * target database type. - * - * @author Vedran Pavic - * @since 1.2.0 - */ -public class JdbcOperationsSessionRepository implements - FindByIndexNameSessionRepository { - - /** - * The default name of database table used by Spring Session to store sessions. - */ - public static final String DEFAULT_TABLE_NAME = "SPRING_SESSION"; - - private static final String SPRING_SECURITY_CONTEXT = "SPRING_SECURITY_CONTEXT"; - - private static final String CREATE_SESSION_QUERY = - "INSERT INTO %TABLE_NAME%(SESSION_ID, CREATION_TIME, LAST_ACCESS_TIME, MAX_INACTIVE_INTERVAL, PRINCIPAL_NAME) " + - "VALUES (?, ?, ?, ?, ?)"; - - private static final String CREATE_SESSION_ATTRIBUTE_QUERY = - "INSERT INTO %TABLE_NAME%_ATTRIBUTES(SESSION_ID, ATTRIBUTE_NAME, ATTRIBUTE_BYTES) " + - "VALUES (?, ?, ?)"; - - private static final String GET_SESSION_QUERY = - "SELECT S.SESSION_ID, S.CREATION_TIME, S.LAST_ACCESS_TIME, S.MAX_INACTIVE_INTERVAL, SA.ATTRIBUTE_NAME, SA.ATTRIBUTE_BYTES " + - "FROM %TABLE_NAME% S " + - "LEFT OUTER JOIN %TABLE_NAME%_ATTRIBUTES SA ON S.SESSION_ID = SA.SESSION_ID " + - "WHERE S.SESSION_ID = ?"; - - private static final String UPDATE_SESSION_QUERY = - "UPDATE %TABLE_NAME% SET LAST_ACCESS_TIME = ?, MAX_INACTIVE_INTERVAL = ?, PRINCIPAL_NAME = ? " + - "WHERE SESSION_ID = ?"; - - private static final String UPDATE_SESSION_ATTRIBUTE_QUERY = - "UPDATE %TABLE_NAME%_ATTRIBUTES SET ATTRIBUTE_BYTES = ? " + - "WHERE SESSION_ID = ? " + - "AND ATTRIBUTE_NAME = ?"; - - private static final String DELETE_SESSION_ATTRIBUTE_QUERY = - "DELETE FROM %TABLE_NAME%_ATTRIBUTES " + - "WHERE SESSION_ID = ? " + - "AND ATTRIBUTE_NAME = ?"; - - private static final String DELETE_SESSION_QUERY = - "DELETE FROM %TABLE_NAME% " + - "WHERE SESSION_ID = ?"; - - private static final String LIST_SESSIONS_BY_PRINCIPAL_NAME_QUERY = - "SELECT S.SESSION_ID, S.CREATION_TIME, S.LAST_ACCESS_TIME, S.MAX_INACTIVE_INTERVAL, SA.ATTRIBUTE_NAME, SA.ATTRIBUTE_BYTES " + - "FROM %TABLE_NAME% S " + - "LEFT OUTER JOIN %TABLE_NAME%_ATTRIBUTES SA ON S.SESSION_ID = SA.SESSION_ID " + - "WHERE S.PRINCIPAL_NAME = ?"; - - private static final String DELETE_SESSIONS_BY_LAST_ACCESS_TIME_QUERY = - "DELETE FROM %TABLE_NAME% " + - "WHERE MAX_INACTIVE_INTERVAL < (? - LAST_ACCESS_TIME) / 1000"; - - private static final Log logger = LogFactory - .getLog(JdbcOperationsSessionRepository.class); - - private static final PrincipalNameResolver PRINCIPAL_NAME_RESOLVER = new PrincipalNameResolver(); - - private final JdbcOperations jdbcOperations; - - private final TransactionOperations transactionOperations; - - private final ResultSetExtractor> extractor = - new ExpiringSessionResultSetExtractor(); - - /** - * The name of database table used by Spring Session to store sessions. - */ - private String tableName = DEFAULT_TABLE_NAME; - - private String createSessionQuery; - - private String createSessionAttributeQuery; - - private String getSessionQuery; - - private String updateSessionQuery; - - private String updateSessionAttributeQuery; - - private String deleteSessionAttributeQuery; - - private String deleteSessionQuery; - - private String listSessionsByPrincipalNameQuery; - - private String deleteSessionsByLastAccessTimeQuery; - - /** - * If non-null, this value is used to override the default value for - * {@link JdbcSession#setMaxInactiveIntervalInSeconds(int)}. - */ - private Integer defaultMaxInactiveInterval; - - private ConversionService conversionService; - - private LobHandler lobHandler = new DefaultLobHandler(); - - /** - * Create a new {@link JdbcOperationsSessionRepository} instance which uses the - * default {@link JdbcOperations} to manage sessions. - * @param dataSource the {@link DataSource} to use - * @param transactionManager the {@link PlatformTransactionManager} to use - */ - public JdbcOperationsSessionRepository(DataSource dataSource, - PlatformTransactionManager transactionManager) { - this(createDefaultJdbcTemplate(dataSource), transactionManager); - } - - /** - * Create a new {@link JdbcOperationsSessionRepository} instance which uses the - * provided {@link JdbcOperations} to manage sessions. - * @param jdbcOperations the {@link JdbcOperations} to use - * @param transactionManager the {@link PlatformTransactionManager} to use - */ - public JdbcOperationsSessionRepository(JdbcOperations jdbcOperations, - PlatformTransactionManager transactionManager) { - Assert.notNull(jdbcOperations, "JdbcOperations must not be null"); - this.jdbcOperations = jdbcOperations; - this.transactionOperations = createTransactionTemplate(transactionManager); - this.conversionService = createDefaultConversionService(); - prepareQueries(); - } - - /** - * Set the name of database table used to store sessions. - * @param tableName the database table name - */ - public void setTableName(String tableName) { - Assert.hasText(tableName, "Table name must not be empty"); - this.tableName = tableName.trim(); - prepareQueries(); - } - - /** - * Set the custom SQL query used to create the session. - * @param createSessionQuery the SQL query string - */ - public void setCreateSessionQuery(String createSessionQuery) { - Assert.hasText(createSessionQuery, "Query must not be empty"); - this.createSessionQuery = createSessionQuery; - } - - /** - * Set the custom SQL query used to create the session attribute. - * @param createSessionAttributeQuery the SQL query string - */ - public void setCreateSessionAttributeQuery(String createSessionAttributeQuery) { - Assert.hasText(createSessionAttributeQuery, "Query must not be empty"); - this.createSessionAttributeQuery = createSessionAttributeQuery; - } - - /** - * Set the custom SQL query used to retrieve the session. - * @param getSessionQuery the SQL query string - */ - public void setGetSessionQuery(String getSessionQuery) { - Assert.hasText(getSessionQuery, "Query must not be empty"); - this.getSessionQuery = getSessionQuery; - } - - /** - * Set the custom SQL query used to update the session. - * @param updateSessionQuery the SQL query string - */ - public void setUpdateSessionQuery(String updateSessionQuery) { - Assert.hasText(updateSessionQuery, "Query must not be empty"); - this.updateSessionQuery = updateSessionQuery; - } - - /** - * Set the custom SQL query used to update the session attribute. - * @param updateSessionAttributeQuery the SQL query string - */ - public void setUpdateSessionAttributeQuery(String updateSessionAttributeQuery) { - Assert.hasText(updateSessionAttributeQuery, "Query must not be empty"); - this.updateSessionAttributeQuery = updateSessionAttributeQuery; - } - - /** - * Set the custom SQL query used to delete the session attribute. - * @param deleteSessionAttributeQuery the SQL query string - */ - public void setDeleteSessionAttributeQuery(String deleteSessionAttributeQuery) { - Assert.hasText(deleteSessionAttributeQuery, "Query must not be empty"); - this.deleteSessionAttributeQuery = deleteSessionAttributeQuery; - } - - /** - * Set the custom SQL query used to delete the session. - * @param deleteSessionQuery the SQL query string - */ - public void setDeleteSessionQuery(String deleteSessionQuery) { - Assert.hasText(deleteSessionQuery, "Query must not be empty"); - this.deleteSessionQuery = deleteSessionQuery; - } - - /** - * Set the custom SQL query used to retrieve the sessions by principal name. - * @param listSessionsByPrincipalNameQuery the SQL query string - */ - public void setListSessionsByPrincipalNameQuery(String listSessionsByPrincipalNameQuery) { - Assert.hasText(listSessionsByPrincipalNameQuery, "Query must not be empty"); - this.listSessionsByPrincipalNameQuery = listSessionsByPrincipalNameQuery; - } - - /** - * Set the custom SQL query used to delete the sessions by last access time. - * @param deleteSessionsByLastAccessTimeQuery the SQL query string - */ - public void setDeleteSessionsByLastAccessTimeQuery(String deleteSessionsByLastAccessTimeQuery) { - Assert.hasText(deleteSessionsByLastAccessTimeQuery, "Query must not be empty"); - this.deleteSessionsByLastAccessTimeQuery = deleteSessionsByLastAccessTimeQuery; - } - - /** - * Set the maximum inactive interval in seconds between requests before newly created - * sessions will be invalidated. A negative time indicates that the session will never - * timeout. The default is 1800 (30 minutes). - * @param defaultMaxInactiveInterval the maximum inactive interval in seconds - */ - public void setDefaultMaxInactiveInterval(Integer defaultMaxInactiveInterval) { - this.defaultMaxInactiveInterval = defaultMaxInactiveInterval; - } - - public void setLobHandler(LobHandler lobHandler) { - Assert.notNull(lobHandler, "LobHandler must not be null"); - this.lobHandler = lobHandler; - } - - /** - * Sets the {@link ConversionService} to use. - * @param conversionService the converter to set - */ - public void setConversionService(ConversionService conversionService) { - Assert.notNull(conversionService, "conversionService must not be null"); - this.conversionService = conversionService; - } - - public JdbcSession createSession() { - JdbcSession session = new JdbcSession(); - if (this.defaultMaxInactiveInterval != null) { - session.setMaxInactiveIntervalInSeconds(this.defaultMaxInactiveInterval); - } - return session; - } - - public void save(final JdbcSession session) { - if (session.isNew()) { - this.transactionOperations.execute(new TransactionCallbackWithoutResult() { - - protected void doInTransactionWithoutResult(TransactionStatus status) { - JdbcOperationsSessionRepository.this.jdbcOperations.update( - JdbcOperationsSessionRepository.this.createSessionQuery, - new PreparedStatementSetter() { - - public void setValues(PreparedStatement ps) throws SQLException { - ps.setString(1, session.getId()); - ps.setLong(2, session.getCreationTime()); - ps.setLong(3, session.getLastAccessedTime()); - ps.setInt(4, session.getMaxInactiveIntervalInSeconds()); - ps.setString(5, session.getPrincipalName()); - } - - }); - if (!session.getAttributeNames().isEmpty()) { - final List attributeNames = new ArrayList(session.getAttributeNames()); - JdbcOperationsSessionRepository.this.jdbcOperations.batchUpdate( - JdbcOperationsSessionRepository.this.createSessionAttributeQuery, - new BatchPreparedStatementSetter() { - - public void setValues(PreparedStatement ps, int i) throws SQLException { - String attributeName = attributeNames.get(i); - ps.setString(1, session.getId()); - ps.setString(2, attributeName); - serialize(ps, 3, session.getAttribute(attributeName)); - } - - public int getBatchSize() { - return attributeNames.size(); - } - - }); - } - } - - }); - } - else { - this.transactionOperations.execute(new TransactionCallbackWithoutResult() { - - protected void doInTransactionWithoutResult(TransactionStatus status) { - if (session.isChanged()) { - JdbcOperationsSessionRepository.this.jdbcOperations.update( - JdbcOperationsSessionRepository.this.updateSessionQuery, - new PreparedStatementSetter() { - - public void setValues(PreparedStatement ps) - throws SQLException { - ps.setLong(1, session.getLastAccessedTime()); - ps.setInt(2, session.getMaxInactiveIntervalInSeconds()); - ps.setString(3, session.getPrincipalName()); - ps.setString(4, session.getId()); - } - - }); - } - Map delta = session.getDelta(); - if (!delta.isEmpty()) { - for (final Map.Entry entry : delta.entrySet()) { - if (entry.getValue() == null) { - JdbcOperationsSessionRepository.this.jdbcOperations.update( - JdbcOperationsSessionRepository.this.deleteSessionAttributeQuery, - new PreparedStatementSetter() { - - public void setValues(PreparedStatement ps) throws SQLException { - ps.setString(1, session.getId()); - ps.setString(2, entry.getKey()); - } - - }); - } - else { - int updatedCount = JdbcOperationsSessionRepository.this.jdbcOperations.update( - JdbcOperationsSessionRepository.this.updateSessionAttributeQuery, - new PreparedStatementSetter() { - - public void setValues(PreparedStatement ps) throws SQLException { - serialize(ps, 1, entry.getValue()); - ps.setString(2, session.getId()); - ps.setString(3, entry.getKey()); - } - - }); - if (updatedCount == 0) { - JdbcOperationsSessionRepository.this.jdbcOperations.update( - JdbcOperationsSessionRepository.this.createSessionAttributeQuery, - new PreparedStatementSetter() { - - public void setValues(PreparedStatement ps) throws SQLException { - ps.setString(1, session.getId()); - ps.setString(2, entry.getKey()); - serialize(ps, 3, entry.getValue()); - } - - }); - } - } - } - } - } - - }); - } - session.clearChangeFlags(); - } - - public JdbcSession getSession(final String id) { - final ExpiringSession session = this.transactionOperations.execute(new TransactionCallback() { - - public ExpiringSession doInTransaction(TransactionStatus status) { - List sessions = JdbcOperationsSessionRepository.this.jdbcOperations.query( - JdbcOperationsSessionRepository.this.getSessionQuery, - new PreparedStatementSetter() { - - public void setValues(PreparedStatement ps) throws SQLException { - ps.setString(1, id); - } - - }, - JdbcOperationsSessionRepository.this.extractor - ); - if (sessions.isEmpty()) { - return null; - } - return sessions.get(0); - } - - }); - - if (session != null) { - if (session.isExpired()) { - delete(id); - } - else { - return new JdbcSession(session); - } - } - return null; - } - - public void delete(final String id) { - this.transactionOperations.execute(new TransactionCallbackWithoutResult() { - - protected void doInTransactionWithoutResult(TransactionStatus status) { - JdbcOperationsSessionRepository.this.jdbcOperations.update( - JdbcOperationsSessionRepository.this.deleteSessionQuery, id); - } - - }); - } - - public Map findByIndexNameAndIndexValue(String indexName, - final String indexValue) { - if (!PRINCIPAL_NAME_INDEX_NAME.equals(indexName)) { - return Collections.emptyMap(); - } - - List sessions = this.transactionOperations.execute(new TransactionCallback>() { - - public List doInTransaction(TransactionStatus status) { - return JdbcOperationsSessionRepository.this.jdbcOperations.query( - JdbcOperationsSessionRepository.this.listSessionsByPrincipalNameQuery, - new PreparedStatementSetter() { - - public void setValues(PreparedStatement ps) throws SQLException { - ps.setString(1, indexValue); - } - - }, - JdbcOperationsSessionRepository.this.extractor - ); - } - - }); - - Map sessionMap = new HashMap( - sessions.size()); - - for (ExpiringSession session : sessions) { - sessionMap.put(session.getId(), new JdbcSession(session)); - } - - return sessionMap; - } - - @Scheduled(cron = "${spring.session.cleanup.cron.expression:0 * * * * *}") - public void cleanUpExpiredSessions() { - int deletedCount = this.transactionOperations.execute(new TransactionCallback() { - - public Integer doInTransaction(TransactionStatus transactionStatus) { - return JdbcOperationsSessionRepository.this.jdbcOperations.update( - JdbcOperationsSessionRepository.this.deleteSessionsByLastAccessTimeQuery, - System.currentTimeMillis()); - } - - }); - - if (logger.isDebugEnabled()) { - logger.debug("Cleaned up " + deletedCount + " expired sessions"); - } - } - - private static JdbcTemplate createDefaultJdbcTemplate(DataSource dataSource) { - JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); - jdbcTemplate.afterPropertiesSet(); - return jdbcTemplate; - } - - private static TransactionTemplate createTransactionTemplate( - PlatformTransactionManager transactionManager) { - TransactionTemplate transactionTemplate = new TransactionTemplate( - transactionManager); - transactionTemplate.setPropagationBehavior( - TransactionDefinition.PROPAGATION_REQUIRES_NEW); - transactionTemplate.afterPropertiesSet(); - return transactionTemplate; - } - - private static GenericConversionService createDefaultConversionService() { - GenericConversionService converter = new GenericConversionService(); - converter.addConverter(Object.class, byte[].class, - new SerializingConverter()); - converter.addConverter(byte[].class, Object.class, - new DeserializingConverter()); - return converter; - } - - private String getQuery(String base) { - return StringUtils.replace(base, "%TABLE_NAME%", this.tableName); - } - - private void prepareQueries() { - this.createSessionQuery = getQuery(CREATE_SESSION_QUERY); - this.createSessionAttributeQuery = getQuery(CREATE_SESSION_ATTRIBUTE_QUERY); - this.getSessionQuery = getQuery(GET_SESSION_QUERY); - this.updateSessionQuery = getQuery(UPDATE_SESSION_QUERY); - this.updateSessionAttributeQuery = getQuery(UPDATE_SESSION_ATTRIBUTE_QUERY); - this.deleteSessionAttributeQuery = getQuery(DELETE_SESSION_ATTRIBUTE_QUERY); - this.deleteSessionQuery = getQuery(DELETE_SESSION_QUERY); - this.listSessionsByPrincipalNameQuery = - getQuery(LIST_SESSIONS_BY_PRINCIPAL_NAME_QUERY); - this.deleteSessionsByLastAccessTimeQuery = - getQuery(DELETE_SESSIONS_BY_LAST_ACCESS_TIME_QUERY); - } - - private void serialize(PreparedStatement ps, int paramIndex, Object attributeValue) - throws SQLException { - this.lobHandler.getLobCreator().setBlobAsBytes(ps, paramIndex, - (byte[]) this.conversionService.convert(attributeValue, - TypeDescriptor.valueOf(Object.class), - TypeDescriptor.valueOf(byte[].class))); - } - - private Object deserialize(ResultSet rs, String columnName) - throws SQLException { - return this.conversionService.convert( - this.lobHandler.getBlobAsBytes(rs, columnName), - TypeDescriptor.valueOf(byte[].class), - TypeDescriptor.valueOf(Object.class)); - } - - /** - * The {@link ExpiringSession} to use for {@link JdbcOperationsSessionRepository}. - * - * @author Vedran Pavic - */ - final class JdbcSession implements ExpiringSession { - - private final ExpiringSession delegate; - - private boolean isNew; - - private boolean changed; - - private Map delta = new HashMap(); - - JdbcSession() { - this.delegate = new MapSession(); - this.isNew = true; - } - - JdbcSession(ExpiringSession delegate) { - Assert.notNull(delegate, "ExpiringSession cannot be null"); - this.delegate = delegate; - } - - boolean isNew() { - return this.isNew; - } - - boolean isChanged() { - return this.changed; - } - - Map getDelta() { - return this.delta; - } - - void clearChangeFlags() { - this.isNew = false; - this.changed = false; - this.delta.clear(); - } - - String getPrincipalName() { - return PRINCIPAL_NAME_RESOLVER.resolvePrincipal(this); - } - - public String getId() { - return this.delegate.getId(); - } - - public T getAttribute(String attributeName) { - return this.delegate.getAttribute(attributeName); - } - - public Set getAttributeNames() { - return this.delegate.getAttributeNames(); - } - - public void setAttribute(String attributeName, Object attributeValue) { - this.delegate.setAttribute(attributeName, attributeValue); - this.delta.put(attributeName, attributeValue); - if (PRINCIPAL_NAME_INDEX_NAME.equals(attributeName) || - SPRING_SECURITY_CONTEXT.equals(attributeName)) { - this.changed = true; - } - } - - public void removeAttribute(String attributeName) { - this.delegate.removeAttribute(attributeName); - this.delta.put(attributeName, null); - } - - public long getCreationTime() { - return this.delegate.getCreationTime(); - } - - public void setLastAccessedTime(long lastAccessedTime) { - this.delegate.setLastAccessedTime(lastAccessedTime); - this.changed = true; - } - - public long getLastAccessedTime() { - return this.delegate.getLastAccessedTime(); - } - - public void setMaxInactiveIntervalInSeconds(int interval) { - this.delegate.setMaxInactiveIntervalInSeconds(interval); - this.changed = true; - } - - public int getMaxInactiveIntervalInSeconds() { - return this.delegate.getMaxInactiveIntervalInSeconds(); - } - - public boolean isExpired() { - return this.delegate.isExpired(); - } - - } - - /** - * Resolves the Spring Security principal name. - * - * @author Vedran Pavic - */ - static class PrincipalNameResolver { - - private SpelExpressionParser parser = new SpelExpressionParser(); - - public String resolvePrincipal(Session session) { - String principalName = session.getAttribute(PRINCIPAL_NAME_INDEX_NAME); - if (principalName != null) { - return principalName; - } - Object authentication = session.getAttribute(SPRING_SECURITY_CONTEXT); - if (authentication != null) { - Expression expression = this.parser - .parseExpression("authentication?.name"); - return expression.getValue(authentication, String.class); - } - return null; - } - - } - - private class ExpiringSessionResultSetExtractor - implements ResultSetExtractor> { - - public List extractData(ResultSet rs) throws SQLException, DataAccessException { - List sessions = new ArrayList(); - while (rs.next()) { - String id = rs.getString("SESSION_ID"); - MapSession session; - if (sessions.size() > 0 && getLast(sessions).getId().equals(id)) { - session = (MapSession) getLast(sessions); - } - else { - session = new MapSession(id); - session.setCreationTime(rs.getLong("CREATION_TIME")); - session.setLastAccessedTime(rs.getLong("LAST_ACCESS_TIME")); - session.setMaxInactiveIntervalInSeconds(rs.getInt("MAX_INACTIVE_INTERVAL")); - } - String attributeName = rs.getString("ATTRIBUTE_NAME"); - if (attributeName != null) { - session.setAttribute(attributeName, deserialize(rs, "ATTRIBUTE_BYTES")); - } - sessions.add(session); - } - return sessions; - } - - private ExpiringSession getLast(List sessions) { - return sessions.get(sessions.size() - 1); - } - - } - -} diff --git a/spring-session/src/main/java/org/springframework/session/jdbc/config/annotation/web/http/EnableJdbcHttpSession.java b/spring-session/src/main/java/org/springframework/session/jdbc/config/annotation/web/http/EnableJdbcHttpSession.java deleted file mode 100644 index ac6271d..0000000 --- a/spring-session/src/main/java/org/springframework/session/jdbc/config/annotation/web/http/EnableJdbcHttpSession.java +++ /dev/null @@ -1,90 +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.jdbc.config.annotation.web.http; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; -import org.springframework.session.MapSession; -import org.springframework.session.config.annotation.web.http.EnableSpringHttpSession; -import org.springframework.session.jdbc.JdbcOperationsSessionRepository; - -/** - * Add this annotation to an {@code @Configuration} class to expose the - * SessionRepositoryFilter as a bean named "springSessionRepositoryFilter" and backed by a - * relational database. In order to leverage the annotation, a single - * {@link javax.sql.DataSource} must be provided. For example: - * - *
- * @Configuration
- * @EnableJdbcHttpSession
- * public class JdbcHttpSessionConfig {
- *
- *     @Bean
- *     public DataSource dataSource() {
- *         return new EmbeddedDatabaseBuilder()
- *                 .setType(EmbeddedDatabaseType.H2)
- *                 .addScript("org/springframework/session/jdbc/schema-h2.sql")
- *                 .build();
- *     }
- *
- *     @Bean
- *     public PlatformTransactionManager transactionManager(DataSource dataSource) {
- *         return new DataSourceTransactionManager(dataSource);
- *     }
- *
- * }
- * 
- * - * More advanced configurations can extend {@link JdbcHttpSessionConfiguration} instead. - * - * For additional information on how to configure data access related concerns, please - * refer to the - * - * Spring Framework Reference Documentation. - * - * @author Vedran Pavic - * @since 1.2.0 - * @see EnableSpringHttpSession - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.TYPE) -@Documented -@Import(JdbcHttpSessionConfiguration.class) -@Configuration -public @interface EnableJdbcHttpSession { - - /** - * The name of database table used by Spring Session to store sessions. - * @return the database table name - */ - String tableName() default JdbcOperationsSessionRepository.DEFAULT_TABLE_NAME; - - /** - * The session timeout in seconds. By default, it is set to 1800 seconds (30 minutes). - * This should be a non-negative integer. - * - * @return the seconds a session can be inactive before expiring - */ - int maxInactiveIntervalInSeconds() default MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS; - -} diff --git a/spring-session/src/main/java/org/springframework/session/jdbc/config/annotation/web/http/JdbcHttpSessionConfiguration.java b/spring-session/src/main/java/org/springframework/session/jdbc/config/annotation/web/http/JdbcHttpSessionConfiguration.java deleted file mode 100644 index 759df03..0000000 --- a/spring-session/src/main/java/org/springframework/session/jdbc/config/annotation/web/http/JdbcHttpSessionConfiguration.java +++ /dev/null @@ -1,195 +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.jdbc.config.annotation.web.http; - -import java.util.Map; - -import javax.sql.DataSource; - -import org.springframework.beans.factory.BeanClassLoaderAware; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.context.EmbeddedValueResolverAware; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.ImportAware; -import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; -import org.springframework.core.annotation.AnnotationAttributes; -import org.springframework.core.convert.ConversionService; -import org.springframework.core.convert.support.GenericConversionService; -import org.springframework.core.serializer.support.DeserializingConverter; -import org.springframework.core.serializer.support.SerializingConverter; -import org.springframework.core.type.AnnotationMetadata; -import org.springframework.jdbc.core.JdbcOperations; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.jdbc.support.lob.LobHandler; -import org.springframework.scheduling.annotation.EnableScheduling; -import org.springframework.session.config.annotation.web.http.SpringHttpSessionConfiguration; -import org.springframework.session.jdbc.JdbcOperationsSessionRepository; -import org.springframework.transaction.PlatformTransactionManager; -import org.springframework.util.ClassUtils; -import org.springframework.util.StringUtils; -import org.springframework.util.StringValueResolver; - -/** - * Spring @Configuration class used to configure and initialize a JDBC based HttpSession - * provider implementation in Spring Session. - *

- * Exposes the {@link org.springframework.session.web.http.SessionRepositoryFilter} as a - * bean named "springSessionRepositoryFilter". In order to use this a single - * {@link DataSource} must be exposed as a Bean. - * - * @author Vedran Pavic - * @author Eddú Meléndez - * @since 1.2.0 - * @see EnableJdbcHttpSession - */ -@Configuration -@EnableScheduling -public class JdbcHttpSessionConfiguration extends SpringHttpSessionConfiguration - implements BeanClassLoaderAware, ImportAware, EmbeddedValueResolverAware { - - private String tableName; - - private Integer maxInactiveIntervalInSeconds; - - private LobHandler lobHandler; - - @Autowired(required = false) - @Qualifier("conversionService") - private ConversionService conversionService; - - private ConversionService springSessionConversionService; - - private ClassLoader classLoader; - - private StringValueResolver embeddedValueResolver; - - @Bean - public JdbcTemplate springSessionJdbcOperations(DataSource dataSource) { - return new JdbcTemplate(dataSource); - } - - @Bean - public JdbcOperationsSessionRepository sessionRepository( - @Qualifier("springSessionJdbcOperations") JdbcOperations jdbcOperations, - PlatformTransactionManager transactionManager) { - JdbcOperationsSessionRepository sessionRepository = - new JdbcOperationsSessionRepository(jdbcOperations, transactionManager); - String tableName = getTableName(); - if (StringUtils.hasText(tableName)) { - sessionRepository.setTableName(tableName); - } - sessionRepository - .setDefaultMaxInactiveInterval(this.maxInactiveIntervalInSeconds); - if (this.lobHandler != null) { - sessionRepository.setLobHandler(this.lobHandler); - } - if (this.springSessionConversionService != null) { - sessionRepository.setConversionService(this.springSessionConversionService); - } - else if (this.conversionService != null) { - sessionRepository.setConversionService(this.conversionService); - } - else if (deserializingConverterSupportsCustomClassLoader()) { - GenericConversionService conversionService = createConversionServiceWithBeanClassLoader(); - sessionRepository.setConversionService(conversionService); - } - return sessionRepository; - } - - /** - * This must be a separate method because some ClassLoaders load the entire method - * definition even if an if statement guards against it loading. This means that older - * versions of Spring would cause a NoSuchMethodError if this were defined in - * {@link #sessionRepository(JdbcOperations, PlatformTransactionManager)}. - * - * @return the default {@link ConversionService} - */ - private GenericConversionService createConversionServiceWithBeanClassLoader() { - GenericConversionService conversionService = new GenericConversionService(); - conversionService.addConverter(Object.class, byte[].class, - new SerializingConverter()); - conversionService.addConverter(byte[].class, Object.class, - new DeserializingConverter(this.classLoader)); - return conversionService; - } - - /* (non-Javadoc) - * @see org.springframework.beans.factory.BeanClassLoaderAware#setBeanClassLoader(java.lang.ClassLoader) - */ - public void setBeanClassLoader(ClassLoader classLoader) { - this.classLoader = classLoader; - } - - @Autowired(required = false) - @Qualifier("springSessionLobHandler") - public void setLobHandler(LobHandler lobHandler) { - this.lobHandler = lobHandler; - } - - @Autowired(required = false) - @Qualifier("springSessionConversionService") - public void setSpringSessionConversionService(ConversionService conversionService) { - this.springSessionConversionService = conversionService; - } - - public void setTableName(String tableName) { - this.tableName = tableName; - } - - public void setMaxInactiveIntervalInSeconds(Integer maxInactiveIntervalInSeconds) { - this.maxInactiveIntervalInSeconds = maxInactiveIntervalInSeconds; - } - - private String getTableName() { - String systemProperty = System.getProperty("spring.session.jdbc.tableName", ""); - if (StringUtils.hasText(systemProperty)) { - return systemProperty; - } - return this.tableName; - } - - private boolean deserializingConverterSupportsCustomClassLoader() { - return ClassUtils.hasConstructor(DeserializingConverter.class, ClassLoader.class); - } - - public void setImportMetadata(AnnotationMetadata importMetadata) { - Map enableAttrMap = importMetadata - .getAnnotationAttributes(EnableJdbcHttpSession.class.getName()); - AnnotationAttributes enableAttrs = AnnotationAttributes.fromMap(enableAttrMap); - String tableNameValue = enableAttrs.getString("tableName"); - if (StringUtils.hasText(tableNameValue)) { - this.tableName = this.embeddedValueResolver - .resolveStringValue(tableNameValue); - } - this.maxInactiveIntervalInSeconds = enableAttrs - .getNumber("maxInactiveIntervalInSeconds"); - } - - public void setEmbeddedValueResolver(StringValueResolver resolver) { - this.embeddedValueResolver = resolver; - } - - /** - * Property placeholder to process the @Scheduled annotation. - * @return the {@link PropertySourcesPlaceholderConfigurer} to use - */ - @Bean - public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() { - return new PropertySourcesPlaceholderConfigurer(); - } -} diff --git a/spring-session/src/main/java/org/springframework/session/security/SpringSessionBackedSessionInformation.java b/spring-session/src/main/java/org/springframework/session/security/SpringSessionBackedSessionInformation.java deleted file mode 100644 index e789d04..0000000 --- a/spring-session/src/main/java/org/springframework/session/security/SpringSessionBackedSessionInformation.java +++ /dev/null @@ -1,92 +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.security; - -import java.util.Date; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.security.core.context.SecurityContext; -import org.springframework.security.core.session.SessionInformation; - -import org.springframework.session.ExpiringSession; -import org.springframework.session.FindByIndexNameSessionRepository; -import org.springframework.session.Session; -import org.springframework.session.SessionRepository; - -/** - * Ensures that calling {@link #expireNow()} propagates to Spring Session, - * since this session information contains only derived data and is not the authoritative source. - * - * @author Joris Kuipers - * @since 1.3 - */ -class SpringSessionBackedSessionInformation extends SessionInformation { - - static final String EXPIRED_ATTR = SpringSessionBackedSessionInformation.class.getName() + ".EXPIRED"; - - private static final Log logger = LogFactory.getLog(SpringSessionBackedSessionInformation.class); - - private static final String SPRING_SECURITY_CONTEXT = "SPRING_SECURITY_CONTEXT"; - - /** - * Tries to determine the principal's name from the given Session. - * - * @param session Spring Session session - * @return the principal's name, or empty String if it couldn't be determined - */ - private static String resolvePrincipal(Session session) { - String principalName = session.getAttribute(FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME); - if (principalName != null) { - return principalName; - } - SecurityContext securityContext = session.getAttribute(SPRING_SECURITY_CONTEXT); - if (securityContext != null && securityContext.getAuthentication() != null) { - return securityContext.getAuthentication().getName(); - } - return ""; - } - - private final SessionRepository sessionRepository; - - SpringSessionBackedSessionInformation(ExpiringSession session, SessionRepository sessionRepository) { - super(resolvePrincipal(session), session.getId(), new Date(session.getLastAccessedTime())); - this.sessionRepository = sessionRepository; - if (Boolean.TRUE.equals(session.getAttribute(EXPIRED_ATTR))) { - super.expireNow(); - } - } - - @Override - public void expireNow() { - if (logger.isDebugEnabled()) { - logger.debug("Expiring session " + getSessionId() + " for user '" + getPrincipal() + - "', presumably because maximum allowed concurrent sessions was exceeded"); - } - super.expireNow(); - ExpiringSession session = this.sessionRepository.getSession(getSessionId()); - if (session != null) { - session.setAttribute(EXPIRED_ATTR, Boolean.TRUE); - this.sessionRepository.save(session); - } - else { - logger.info("Could not find Session with id " + getSessionId() + " to mark as expired"); - } - } - -} diff --git a/spring-session/src/main/java/org/springframework/session/security/SpringSessionBackedSessionRegistry.java b/spring-session/src/main/java/org/springframework/session/security/SpringSessionBackedSessionRegistry.java deleted file mode 100644 index 8f70e64..0000000 --- a/spring-session/src/main/java/org/springframework/session/security/SpringSessionBackedSessionRegistry.java +++ /dev/null @@ -1,113 +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.security; - -import java.security.Principal; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -import org.springframework.security.core.session.SessionInformation; -import org.springframework.security.core.session.SessionRegistry; -import org.springframework.security.core.userdetails.UserDetails; - -import org.springframework.session.ExpiringSession; -import org.springframework.session.FindByIndexNameSessionRepository; - -import org.springframework.util.Assert; - -/** - * A {@link SessionRegistry} that retrieves session information from Spring Session, rather than maintaining it itself. - * This allows concurrent session management with Spring Security in a clustered environment. - *

- * Relies on being able to derive the same String-based representation of the principal given to - * {@link #getAllSessions(Object, boolean)} as used by Spring Session in order to look up the user's sessions. - *

- * Does not support {@link #getAllPrincipals()}, since that information is not available. - * - * @author Joris Kuipers - * @since 1.3 - */ -public class SpringSessionBackedSessionRegistry implements SessionRegistry { - - private final FindByIndexNameSessionRepository sessionRepository; - - public SpringSessionBackedSessionRegistry(FindByIndexNameSessionRepository sessionRepository) { - Assert.notNull(sessionRepository, "sessionRepository cannot be null"); - this.sessionRepository = sessionRepository; - } - - public List getAllPrincipals() { - throw new UnsupportedOperationException("SpringSessionBackedSessionRegistry does not support retrieving all principals, " + - "since Spring Session provides no way to obtain that information"); - } - - public List getAllSessions(Object principal, boolean includeExpiredSessions) { - Collection sessions = - this.sessionRepository.findByIndexNameAndIndexValue(FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, name(principal)).values(); - List infos = new ArrayList(); - for (ExpiringSession session : sessions) { - if (includeExpiredSessions || !Boolean.TRUE.equals(session.getAttribute(SpringSessionBackedSessionInformation.EXPIRED_ATTR))) { - infos.add(new SpringSessionBackedSessionInformation(session, this.sessionRepository)); - } - } - return infos; - } - - public SessionInformation getSessionInformation(String sessionId) { - ExpiringSession session = this.sessionRepository.getSession(sessionId); - if (session != null) { - return new SpringSessionBackedSessionInformation(session, this.sessionRepository); - } - return null; - } - - /* - * This is a no-op, as we don't administer sessions ourselves. - */ - public void refreshLastRequest(String sessionId) { - } - - /* - * This is a no-op, as we don't administer sessions ourselves. - */ - public void registerNewSession(String sessionId, Object principal) { - } - - /* - * This is a no-op, as we don't administer sessions ourselves. - */ - public void removeSessionInformation(String sessionId) { - } - - /** - * Derives a String name for the given principal. - * - * @param principal as provided by Spring Security - * @return name of the principal, or its {@code toString()} representation if no name could be derived - */ - protected String name(Object principal) { - if (principal instanceof UserDetails) { - return ((UserDetails) principal).getUsername(); - } - if (principal instanceof Principal) { - return ((Principal) principal).getName(); - } - return principal.toString(); - } -} diff --git a/spring-session/src/main/java/org/springframework/session/security/web/authentication/SpringSessionRememberMeServices.java b/spring-session/src/main/java/org/springframework/session/security/web/authentication/SpringSessionRememberMeServices.java deleted file mode 100644 index abda5ac..0000000 --- a/spring-session/src/main/java/org/springframework/session/security/web/authentication/SpringSessionRememberMeServices.java +++ /dev/null @@ -1,141 +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.security.web.authentication; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.security.core.Authentication; -import org.springframework.security.web.authentication.RememberMeServices; -import org.springframework.security.web.authentication.logout.LogoutHandler; -import org.springframework.security.web.context.HttpSessionSecurityContextRepository; -import org.springframework.util.Assert; - -/** - * A {@link RememberMeServices} implementation that uses Spring Session backed - * {@link HttpSession} to provide remember-me service capabilities. - * - * @author Vedran Pavic - * @since 1.3.0 - */ -public class SpringSessionRememberMeServices - implements RememberMeServices, LogoutHandler { - - /** - * Remember-me login request attribute name. - */ - public static final String REMEMBER_ME_LOGIN_ATTR = SpringSessionRememberMeServices.class - .getName() + "REMEMBER_ME_LOGIN_ATTR"; - - private static final String DEFAULT_REMEMBERME_PARAMETER = "remember-me"; - - private static final int THIRTY_DAYS_SECONDS = 2592000; - - private static final Log logger = LogFactory - .getLog(SpringSessionRememberMeServices.class); - - private String rememberMeParameterName = DEFAULT_REMEMBERME_PARAMETER; - - private boolean alwaysRemember; - - private int validitySeconds = THIRTY_DAYS_SECONDS; - - private String sessionAttrToDeleteOnLoginFail = HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY; - - public final Authentication autoLogin(HttpServletRequest request, - HttpServletResponse response) { - return null; - } - - public final void loginFail(HttpServletRequest request, - HttpServletResponse response) { - logout(request); - } - - public final void loginSuccess(HttpServletRequest request, - HttpServletResponse response, Authentication successfulAuthentication) { - if (!this.alwaysRemember - && !rememberMeRequested(request, this.rememberMeParameterName)) { - logger.debug("Remember-me login not requested."); - return; - } - request.setAttribute(REMEMBER_ME_LOGIN_ATTR, true); - request.getSession().setMaxInactiveInterval(this.validitySeconds); - } - - /** - * Allows customization of whether a remember-me login has been requested. The default - * is to return {@code true} if the configured parameter name has been included in the - * request and is set to the value {@code true}. - * @param request the request submitted from an interactive login, which may include - * additional information indicating that a persistent login is desired. - * @param parameter the configured remember-me parameter name. - * @return true if the request includes information indicating that a persistent login - * has been requested. - */ - protected boolean rememberMeRequested(HttpServletRequest request, String parameter) { - String rememberMe = request.getParameter(parameter); - if (rememberMe != null) { - if (rememberMe.equalsIgnoreCase("true") || rememberMe.equalsIgnoreCase("on") - || rememberMe.equalsIgnoreCase("yes") || rememberMe.equals("1")) { - return true; - } - } - if (logger.isDebugEnabled()) { - logger.debug("Did not send remember-me cookie (principal did not set " - + "parameter '" + parameter + "')"); - } - return false; - } - - /** - * Set the name of the parameter which should be checked for to see if a remember-me - * has been requested during a login request. This should be the same name you assign - * to the checkbox in your login form. - * @param rememberMeParameterName the request parameter - */ - public void setRememberMeParameterName(String rememberMeParameterName) { - Assert.hasText(rememberMeParameterName, - "rememberMeParameterName cannot be empty or null"); - this.rememberMeParameterName = rememberMeParameterName; - } - - public void setAlwaysRemember(boolean alwaysRemember) { - this.alwaysRemember = alwaysRemember; - } - - public void setValiditySeconds(int validitySeconds) { - this.validitySeconds = validitySeconds; - } - - public void logout(HttpServletRequest request, HttpServletResponse response, - Authentication authentication) { - logout(request); - } - - private void logout(HttpServletRequest request) { - logger.debug("Interactive login attempt was unsuccessful."); - HttpSession session = request.getSession(false); - if (session != null) { - session.removeAttribute(this.sessionAttrToDeleteOnLoginFail); - } - } -} diff --git a/spring-session/src/main/java/org/springframework/session/web/context/AbstractHttpSessionApplicationInitializer.java b/spring-session/src/main/java/org/springframework/session/web/context/AbstractHttpSessionApplicationInitializer.java deleted file mode 100644 index ec2b751..0000000 --- a/spring-session/src/main/java/org/springframework/session/web/context/AbstractHttpSessionApplicationInitializer.java +++ /dev/null @@ -1,286 +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.context; - -import java.util.Arrays; -import java.util.EnumSet; - -import javax.servlet.DispatcherType; -import javax.servlet.Filter; -import javax.servlet.FilterRegistration.Dynamic; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; - -import org.springframework.context.ApplicationContext; -import org.springframework.core.Conventions; -import org.springframework.core.Ordered; -import org.springframework.core.annotation.Order; -import org.springframework.util.Assert; -import org.springframework.web.WebApplicationInitializer; -import org.springframework.web.context.AbstractContextLoaderInitializer; -import org.springframework.web.context.ContextLoaderListener; -import org.springframework.web.context.WebApplicationContext; -import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; -import org.springframework.web.filter.DelegatingFilterProxy; - -/** - * Registers the {@link DelegatingFilterProxy} to use the springSessionRepositoryFilter - * before any other registered {@link Filter}. When used with - * {@link #AbstractHttpSessionApplicationInitializer(Class...)}, it will also register a - * {@link ContextLoaderListener}. When used with - * {@link #AbstractHttpSessionApplicationInitializer()}, this class is typically used in - * addition to a subclass of {@link AbstractContextLoaderInitializer}. - * - *

- * By default the {@link DelegatingFilterProxy} is registered with support for - * asynchronous requests, but can be enabled by overriding - * {@link #isAsyncSessionSupported()} and {@link #getSessionDispatcherTypes()}. - *

- * - *

- * Additional configuration before and after the springSecurityFilterChain can be added by - * overriding {@link #afterSessionRepositoryFilter(ServletContext)}. - *

- * - * - *

Caveats

- *

- * Subclasses of {@code AbstractDispatcherServletInitializer} will register their filters - * before any other {@link Filter}. This means that you will typically want to ensure - * subclasses of {@code AbstractDispatcherServletInitializer} are invoked first. This can - * be done by ensuring the {@link Order} or {@link Ordered} of - * {@code AbstractDispatcherServletInitializer} are sooner than subclasses of - * {@code AbstractSecurityWebApplicationInitializer}. - *

- * - * @author Rob Winch - * - */ -@Order(100) -public abstract class AbstractHttpSessionApplicationInitializer - implements WebApplicationInitializer { - - private static final String SERVLET_CONTEXT_PREFIX = "org.springframework.web.servlet.FrameworkServlet.CONTEXT."; - - /** - * The default name for Spring Session's repository filter. - */ - public static final String DEFAULT_FILTER_NAME = "springSessionRepositoryFilter"; - - private final Class[] configurationClasses; - - /** - * Creates a new instance that assumes the Spring Session configuration is loaded by - * some other means than this class. For example, a user might create a - * {@link ContextLoaderListener} using a subclass of - * {@link AbstractContextLoaderInitializer}. - * - * @see ContextLoaderListener - */ - protected AbstractHttpSessionApplicationInitializer() { - this.configurationClasses = null; - } - - /** - * Creates a new instance that will instantiate the {@link ContextLoaderListener} with - * the specified classes. - * - * @param configurationClasses {@code @Configuration} classes that will be used to - * configure the context - */ - protected AbstractHttpSessionApplicationInitializer( - Class... configurationClasses) { - this.configurationClasses = configurationClasses; - } - - public void onStartup(ServletContext servletContext) throws ServletException { - beforeSessionRepositoryFilter(servletContext); - if (this.configurationClasses != null) { - AnnotationConfigWebApplicationContext rootAppContext = new AnnotationConfigWebApplicationContext(); - rootAppContext.register(this.configurationClasses); - servletContext.addListener(new ContextLoaderListener(rootAppContext)); - } - insertSessionRepositoryFilter(servletContext); - afterSessionRepositoryFilter(servletContext); - } - - /** - * Registers the springSessionRepositoryFilter. - * @param servletContext the {@link ServletContext} - */ - private void insertSessionRepositoryFilter(ServletContext servletContext) { - String filterName = DEFAULT_FILTER_NAME; - DelegatingFilterProxy springSessionRepositoryFilter = new DelegatingFilterProxy( - filterName); - String contextAttribute = getWebApplicationContextAttribute(); - if (contextAttribute != null) { - springSessionRepositoryFilter.setContextAttribute(contextAttribute); - } - registerFilter(servletContext, true, filterName, springSessionRepositoryFilter); - } - - /** - * Inserts the provided {@link Filter}s before existing {@link Filter}s using default - * generated names, {@link #getSessionDispatcherTypes()}, and - * {@link #isAsyncSessionSupported()}. - * - * @param servletContext the {@link ServletContext} to use - * @param filters the {@link Filter}s to register - */ - protected final void insertFilters(ServletContext servletContext, Filter... filters) { - registerFilters(servletContext, true, filters); - } - - /** - * Inserts the provided {@link Filter}s after existing {@link Filter}s using default - * generated names, {@link #getSessionDispatcherTypes()}, and - * {@link #isAsyncSessionSupported()}. - * - * @param servletContext the {@link ServletContext} to use - * @param filters the {@link Filter}s to register - */ - protected final void appendFilters(ServletContext servletContext, Filter... filters) { - registerFilters(servletContext, false, filters); - } - - /** - * Registers the provided {@link Filter}s using default generated names, - * {@link #getSessionDispatcherTypes()}, and {@link #isAsyncSessionSupported()}. - * - * @param servletContext the {@link ServletContext} to use - * @param insertBeforeOtherFilters if true, will insert the provided {@link Filter}s - * before other {@link Filter}s. Otherwise, will insert the {@link Filter}s after - * other {@link Filter}s. - * @param filters the {@link Filter}s to register - */ - private void registerFilters(ServletContext servletContext, - boolean insertBeforeOtherFilters, Filter... filters) { - Assert.notEmpty(filters, "filters cannot be null or empty"); - - for (Filter filter : filters) { - if (filter == null) { - throw new IllegalArgumentException( - "filters cannot contain null values. Got " - + Arrays.asList(filters)); - } - String filterName = Conventions.getVariableName(filter); - registerFilter(servletContext, insertBeforeOtherFilters, filterName, filter); - } - } - - /** - * Registers the provided filter using the {@link #isAsyncSessionSupported()} and - * {@link #getSessionDispatcherTypes()}. - * - * @param servletContext the servlet context - * @param insertBeforeOtherFilters should this Filter be inserted before or after - * other {@link Filter} - * @param filterName the filter name - * @param filter the filter - */ - private void registerFilter(ServletContext servletContext, - boolean insertBeforeOtherFilters, String filterName, Filter filter) { - Dynamic registration = servletContext.addFilter(filterName, filter); - if (registration == null) { - throw new IllegalStateException( - "Duplicate Filter registration for '" + filterName - + "'. Check to ensure the Filter is only configured once."); - } - registration.setAsyncSupported(isAsyncSessionSupported()); - EnumSet dispatcherTypes = getSessionDispatcherTypes(); - registration.addMappingForUrlPatterns(dispatcherTypes, !insertBeforeOtherFilters, - "/*"); - } - - /** - * Returns the {@link DelegatingFilterProxy#getContextAttribute()} or null if the - * parent {@link ApplicationContext} should be used. The default behavior is to use - * the parent {@link ApplicationContext}. - * - *

- * If {@link #getDispatcherWebApplicationContextSuffix()} is non-null the - * {@link WebApplicationContext} for the Dispatcher will be used. This means the child - * {@link ApplicationContext} is used to look up the springSessionRepositoryFilter - * bean. - *

- * - * @return the {@link DelegatingFilterProxy#getContextAttribute()} or null if the - * parent {@link ApplicationContext} should be used - */ - private String getWebApplicationContextAttribute() { - String dispatcherServletName = getDispatcherWebApplicationContextSuffix(); - if (dispatcherServletName == null) { - return null; - } - return SERVLET_CONTEXT_PREFIX + dispatcherServletName; - } - - /** - * Return the {@code } to use the DispatcherServlet's - * {@link WebApplicationContext} to find the {@link DelegatingFilterProxy} or null to - * use the parent {@link ApplicationContext}. - * - *

- * For example, if you are using AbstractDispatcherServletInitializer or - * AbstractAnnotationConfigDispatcherServletInitializer and using the provided Servlet - * name, you can return "dispatcher" from this method to use the DispatcherServlet's - * {@link WebApplicationContext}. - *

- * - * @return the {@code } of the DispatcherServlet to use its - * {@link WebApplicationContext} or null (default) to use the parent - * {@link ApplicationContext}. - */ - protected String getDispatcherWebApplicationContextSuffix() { - return null; - } - - /** - * Invoked before the springSessionRepositoryFilter is added. - * @param servletContext the {@link ServletContext} - */ - protected void beforeSessionRepositoryFilter(ServletContext servletContext) { - - } - - /** - * Invoked after the springSessionRepositoryFilter is added. - * @param servletContext the {@link ServletContext} - */ - protected void afterSessionRepositoryFilter(ServletContext servletContext) { - - } - - /** - * Get the {@link DispatcherType} for the springSessionRepositoryFilter. - * @return the {@link DispatcherType} for the filter - */ - protected EnumSet getSessionDispatcherTypes() { - return EnumSet.of(DispatcherType.REQUEST, DispatcherType.ERROR, - DispatcherType.ASYNC); - } - - /** - * Determine if the springSessionRepositoryFilter should be marked as supporting - * asynch. Default is true. - * - * @return true if springSessionRepositoryFilter should be marked as supporting asynch - */ - protected boolean isAsyncSessionSupported() { - return true; - } -} diff --git a/spring-session/src/main/java/org/springframework/session/web/http/CookieHttpSessionStrategy.java b/spring-session/src/main/java/org/springframework/session/web/http/CookieHttpSessionStrategy.java deleted file mode 100644 index 02b8c1f..0000000 --- a/spring-session/src/main/java/org/springframework/session/web/http/CookieHttpSessionStrategy.java +++ /dev/null @@ -1,447 +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.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; -import org.springframework.util.Assert; - -/** - * A {@link HttpSessionStrategy} that uses a cookie to obtain the session from. - * Specifically, this implementation will allow specifying a cookie serialization strategy - * using {@link CookieHttpSessionStrategy#setCookieSerializer(CookieSerializer)}. The - * default is cookie name is "SESSION". - * - * When a session is created, the HTTP response will have a cookie with the specified - * cookie name and the value of the session id. The cookie will be marked as a session - * cookie, use the context path for the path of the cookie, marked as HTTPOnly, and if - * {@link javax.servlet.http.HttpServletRequest#isSecure()} returns true, the cookie will - * be marked as secure. For example: - * - *
- * HTTP/1.1 200 OK
- * Set-Cookie: SESSION=f81d4fae-7dec-11d0-a765-00a0c91e6bf6; Path=/context-root; Secure; HttpOnly
- * 
- * - * The client should now include the session in each request by specifying the same cookie - * in their request. For example: - * - *
- * GET /messages/ HTTP/1.1
- * Host: example.com
- * Cookie: SESSION=f81d4fae-7dec-11d0-a765-00a0c91e6bf6
- * 
- * - * When the session is invalidated, the server will send an HTTP response that expires the - * cookie. For example: - * - *
- * HTTP/1.1 200 OK
- * 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.getSession(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 - * @since 1.0 - */ -public final class CookieHttpSessionStrategy - implements MultiHttpSessionStrategy, HttpSessionManager { - /** - * The default delimiter for both serialization and deserialization. - */ - private static final String DEFAULT_DELIMITER = " "; - - 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 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; - } - } - - public void onNewSession(Session session, HttpServletRequest request, - HttpServletResponse response) { - Set sessionIdsWritten = getSessionIdsWritten(request); - if (sessionIdsWritten.contains(session.getId())) { - return; - } - sessionIdsWritten.add(session.getId()); - - Map sessionIds = getSessionIds(request); - String sessionAlias = getCurrentSessionAlias(request); - sessionIds.put(sessionAlias, session.getId()); - - String cookieValue = createSessionCookieValue(sessionIds); - 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(); - } - - StringBuffer buffer = new StringBuffer(); - for (Map.Entry entry : sessionIds.entrySet()) { - String alias = entry.getKey(); - String id = entry.getValue(); - - buffer.append(alias); - buffer.append(this.serializationDelimiter); - buffer.append(id); - buffer.append(this.serializationDelimiter); - } - buffer.deleteCharAt(buffer.length() - 1); - return buffer.toString(); - } - - 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; - } - - /** - * Sets the {@link CookieSerializer} to be used. - * - * @param cookieSerializer the cookieSerializer to set. Cannot be null. - */ - public void setCookieSerializer(CookieSerializer cookieSerializer) { - Assert.notNull(cookieSerializer, "cookieSerializer cannot be null"); - 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/src/main/java/org/springframework/session/web/http/CookieSerializer.java b/spring-session/src/main/java/org/springframework/session/web/http/CookieSerializer.java deleted file mode 100644 index d0e2f4e..0000000 --- a/spring-session/src/main/java/org/springframework/session/web/http/CookieSerializer.java +++ /dev/null @@ -1,109 +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.List; - -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -/** - * Strategy for reading and writing a cookie value to the {@link HttpServletResponse}. - * - * @author Rob Winch - * @since 1.1 - */ -public interface CookieSerializer { - - /** - * Writes a given {@link CookieValue} to the provided {@link HttpServletResponse}. - * - * @param cookieValue the {@link CookieValue} to write to - * {@link CookieValue#getResponse()}. Cannot be null. - */ - void writeCookieValue(CookieValue cookieValue); - - /** - * Reads all the matching cookies from the {@link HttpServletRequest}. The result is a - * List since there can be multiple {@link Cookie} in a single request with a matching - * name. For example, one Cookie may have a path of / and another of /context, but the - * path is not transmitted in the request. - * - * @param request the {@link HttpServletRequest} to read the cookie from. Cannot be - * null. - * @return the values of all the matching cookies - */ - List readCookieValues(HttpServletRequest request); - - /** - * Contains the information necessary to write a value to the - * {@link HttpServletResponse}. - * - * @author Rob Winch - * @since 1.1 - */ - class CookieValue { - private final HttpServletRequest request; - private final HttpServletResponse response; - private final String cookieValue; - - /** - * Creates a new instance. - * - * @param request the {@link HttpServletRequest} to use. Useful for determining - * the context in which the cookie is set. Cannot be null. - * @param response the {@link HttpServletResponse} to use. - * @param cookieValue the value of the cookie to be written. This value may be - * modified by the {@link CookieSerializer} when writing to the actual cookie so - * long as the original value is returned when the cookie is read. - */ - public CookieValue(HttpServletRequest request, HttpServletResponse response, - String cookieValue) { - this.request = request; - this.response = response; - this.cookieValue = cookieValue; - } - - /** - * Gets the request to use. - * @return the request to use. Cannot be null. - */ - public HttpServletRequest getRequest() { - return this.request; - } - - /** - * Gets the response to write to. - * @return the response to write to. Cannot be null. - */ - public HttpServletResponse getResponse() { - return this.response; - } - - /** - * The value to be written. This value may be modified by the - * {@link CookieSerializer} before written to the cookie. However, the value must - * be the same as the original when it is read back in. - * - * @return the value to be written - */ - public String getCookieValue() { - return this.cookieValue; - } - } -} diff --git a/spring-session/src/main/java/org/springframework/session/web/http/DefaultCookieSerializer.java b/spring-session/src/main/java/org/springframework/session/web/http/DefaultCookieSerializer.java deleted file mode 100644 index b2c0abc..0000000 --- a/spring-session/src/main/java/org/springframework/session/web/http/DefaultCookieSerializer.java +++ /dev/null @@ -1,353 +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.web.http; - -import java.util.ArrayList; -import java.util.Base64; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import javax.servlet.ServletRequest; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -/** - * The default implementation of {@link CookieSerializer}. - * - * @author Rob Winch - * @author Vedran Pavic - * @author Eddú Meléndez - * @since 1.1 - */ -public class DefaultCookieSerializer implements CookieSerializer { - - private String cookieName = "SESSION"; - - private Boolean useSecureCookie; - - private boolean useHttpOnlyCookie = isServlet3(); - - private String cookiePath; - - private int cookieMaxAge = -1; - - private String domainName; - - private Pattern domainNamePattern; - - private String jvmRoute; - - private boolean useBase64Encoding = true; - - private String rememberMeRequestAttribute; - - /* - * (non-Javadoc) - * - * @see org.springframework.session.web.http.CookieSerializer#readCookieValues(javax. - * servlet.http.HttpServletRequest) - */ - public List readCookieValues(HttpServletRequest request) { - Cookie[] cookies = request.getCookies(); - List matchingCookieValues = new ArrayList(); - if (cookies != null) { - for (Cookie cookie : cookies) { - if (this.cookieName.equals(cookie.getName())) { - String sessionId = this.useBase64Encoding - ? base64Decode(cookie.getValue()) : cookie.getValue(); - if (sessionId == null) { - continue; - } - if (this.jvmRoute != null && sessionId.endsWith(this.jvmRoute)) { - sessionId = sessionId.substring(0, - sessionId.length() - this.jvmRoute.length()); - } - matchingCookieValues.add(sessionId); - } - } - } - return matchingCookieValues; - } - - /* - * (non-Javadoc) - * - * @see org.springframework.session.web.http.CookieWriter#writeCookieValue(org. - * springframework.session.web.http.CookieWriter.CookieValue) - */ - public void writeCookieValue(CookieValue cookieValue) { - HttpServletRequest request = cookieValue.getRequest(); - HttpServletResponse response = cookieValue.getResponse(); - - String requestedCookieValue = cookieValue.getCookieValue(); - String actualCookieValue = this.jvmRoute == null ? requestedCookieValue - : requestedCookieValue + this.jvmRoute; - - Cookie sessionCookie = new Cookie(this.cookieName, this.useBase64Encoding - ? base64Encode(actualCookieValue) : actualCookieValue); - sessionCookie.setSecure(isSecureCookie(request)); - sessionCookie.setPath(getCookiePath(request)); - String domainName = getDomainName(request); - if (domainName != null) { - sessionCookie.setDomain(domainName); - } - - if (this.useHttpOnlyCookie) { - sessionCookie.setHttpOnly(true); - } - - if ("".equals(requestedCookieValue)) { - sessionCookie.setMaxAge(0); - } - else if (this.rememberMeRequestAttribute != null - && request.getAttribute(this.rememberMeRequestAttribute) != null) { - // the cookie is only written at time of session creation, so we rely on - // session expiration rather than cookie expiration if remember me is enabled - sessionCookie.setMaxAge(Integer.MAX_VALUE); - } - else { - sessionCookie.setMaxAge(this.cookieMaxAge); - } - - response.addCookie(sessionCookie); - } - - /** - * Decode the value using Base64. - * @param base64Value the Base64 String to decode - * @return the Base64 decoded value - * @since 1.2.2 - */ - private String base64Decode(String base64Value) { - try { - byte[] decodedCookieBytes = Base64.getDecoder().decode(base64Value); - return new String(decodedCookieBytes); - } - catch (Exception e) { - return null; - } - } - - /** - * Encode the value using Base64. - * @param value the String to Base64 encode - * @return the Base64 encoded value - * @since 1.2.2 - */ - private String base64Encode(String value) { - byte[] encodedCookieBytes = Base64.getEncoder().encode(value.getBytes()); - return new String(encodedCookieBytes); - } - - /** - * Sets if a Cookie marked as secure should be used. The default is to use the value - * of {@link HttpServletRequest#isSecure()}. - * - * @param useSecureCookie determines if the cookie should be marked as secure. - */ - public void setUseSecureCookie(boolean useSecureCookie) { - this.useSecureCookie = useSecureCookie; - } - - /** - * Sets if a Cookie marked as HTTP Only should be used. The default is true in Servlet - * 3+ environments, else false. - * - * @param useHttpOnlyCookie determines if the cookie should be marked as HTTP Only. - */ - public void setUseHttpOnlyCookie(boolean useHttpOnlyCookie) { - if (useHttpOnlyCookie && !isServlet3()) { - throw new IllegalArgumentException( - "You cannot set useHttpOnlyCookie to true in pre Servlet 3 environment"); - } - this.useHttpOnlyCookie = useHttpOnlyCookie; - } - - private boolean isSecureCookie(HttpServletRequest request) { - if (this.useSecureCookie == null) { - return request.isSecure(); - } - return this.useSecureCookie; - } - - /** - * Sets the path of the Cookie. The default is to use the context path from the - * {@link HttpServletRequest}. - * - * @param cookiePath the path of the Cookie. If null, the default of the context path - * will be used. - */ - public void setCookiePath(String cookiePath) { - this.cookiePath = cookiePath; - } - - public void setCookieName(String cookieName) { - if (cookieName == null) { - throw new IllegalArgumentException("cookieName cannot be null"); - } - this.cookieName = cookieName; - } - - /** - * Sets the maxAge property of the Cookie. The default is -1 which signals to delete - * the cookie when the browser is closed. - * - * @param cookieMaxAge the maxAge property of the Cookie - */ - public void setCookieMaxAge(int cookieMaxAge) { - this.cookieMaxAge = cookieMaxAge; - } - - /** - * Sets an explicit Domain Name. This allow the domain of "example.com" to be used - * when the request comes from www.example.com. This allows for sharing the cookie - * across subdomains. The default is to use the current domain. - * - * @param domainName the name of the domain to use. (i.e. "example.com") - * @throws IllegalStateException if the domainNamePattern is also set - */ - public void setDomainName(String domainName) { - if (this.domainNamePattern != null) { - throw new IllegalStateException( - "Cannot set both domainName and domainNamePattern"); - } - this.domainName = domainName; - } - - /** - *

- * Sets a case insensitive pattern used to extract the domain name from the - * {@link HttpServletRequest#getServerName()}. The pattern should provide a single - * grouping that defines what the value is that should be matched. User's should be - * careful not to output malicious characters like new lines to prevent from things - * like HTTP - * Response Splitting. - *

- * - *

- * If the pattern does not match, then no domain will be set. This is useful to ensure - * the domain is not set during development when localhost might be used. - *

- *

- * An example value might be "^.+?\\.(\\w+\\.[a-z]+)$". For the given input, it would - * provide the following explicit domain (null means no domain name is set): - *

- * - *
    - *
  • example.com - null
  • - *
  • child.sub.example.com - example.com
  • - *
  • localhost - null
  • - *
  • 127.0.1.1 - null
  • - *
- * - * @param domainNamePattern the case insensitive pattern to extract the domain name - * with - * @throws IllegalStateException if the domainName is also set - */ - public void setDomainNamePattern(String domainNamePattern) { - if (this.domainName != null) { - throw new IllegalStateException( - "Cannot set both domainName and domainNamePattern"); - } - this.domainNamePattern = Pattern.compile(domainNamePattern, - Pattern.CASE_INSENSITIVE); - } - - /** - *

- * Used to identify which JVM to route to for session affinity. With some - * implementations (i.e. Redis) this provides no performance benefit. However, this - * can help with tracing logs of a particular user. This will ensure that the value of - * the cookie is formatted as - *

- * - * sessionId + "." jvmRoute - * - *

- * To use set a custom route on each JVM instance and setup a frontend proxy to - * forward all requests to the JVM based on the route. - *

- * - * @param jvmRoute the JVM Route to use (i.e. "node01jvmA", "n01ja", etc) - */ - public void setJvmRoute(String jvmRoute) { - this.jvmRoute = "." + jvmRoute; - } - - /** - * Set if the Base64 encoding of cookie value should be used. This is valuable in - * order to support RFC 6265 which - * recommends using Base 64 encoding to the cookie value. - * - * @param useBase64Encoding the flag to indicate whether to use Base64 encoding - */ - public void setUseBase64Encoding(boolean useBase64Encoding) { - this.useBase64Encoding = useBase64Encoding; - } - - /** - * Set the request attribute name that indicates remember-me login. If specified, the - * cookie will be written as Integer.MAX_VALUE. - * @param rememberMeRequestAttribute the remember-me request attribute name - * @since 1.3.0 - */ - public void setRememberMeRequestAttribute(String rememberMeRequestAttribute) { - if (rememberMeRequestAttribute == null) { - throw new IllegalArgumentException( - "rememberMeRequestAttribute cannot be null"); - } - this.rememberMeRequestAttribute = rememberMeRequestAttribute; - } - - private String getDomainName(HttpServletRequest request) { - if (this.domainName != null) { - return this.domainName; - } - if (this.domainNamePattern != null) { - Matcher matcher = this.domainNamePattern.matcher(request.getServerName()); - if (matcher.matches()) { - return matcher.group(1); - } - } - return null; - } - - private String getCookiePath(HttpServletRequest request) { - if (this.cookiePath == null) { - return request.getContextPath() + "/"; - } - return this.cookiePath; - } - - /** - * Returns true if the Servlet 3 APIs are detected. - * - * @return whether the Servlet 3 APIs are detected - */ - private boolean isServlet3() { - try { - ServletRequest.class.getMethod("startAsync"); - return true; - } - catch (NoSuchMethodException e) { - } - return false; - } - -} diff --git a/spring-session/src/main/java/org/springframework/session/web/http/ExpiringSessionHttpSession.java b/spring-session/src/main/java/org/springframework/session/web/http/ExpiringSessionHttpSession.java deleted file mode 100644 index 36b74f6..0000000 --- a/spring-session/src/main/java/org/springframework/session/web/http/ExpiringSessionHttpSession.java +++ /dev/null @@ -1,165 +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.Collections; -import java.util.Enumeration; -import java.util.NoSuchElementException; -import java.util.Set; - -import javax.servlet.ServletContext; -import javax.servlet.http.HttpSession; -import javax.servlet.http.HttpSessionContext; - -import org.springframework.session.ExpiringSession; - -/** - * Adapts Spring Session's {@link ExpiringSession} to an {@link HttpSession}. - * - * @param the {@link ExpiringSession} type - * @author Rob Winch - * @since 1.1 - */ -@SuppressWarnings("deprecation") -class ExpiringSessionHttpSession implements HttpSession { - private S session; - private final ServletContext servletContext; - private boolean invalidated; - private boolean old; - - ExpiringSessionHttpSession(S session, ServletContext servletContext) { - this.session = session; - this.servletContext = servletContext; - } - - public void setSession(S session) { - this.session = session; - } - - public S getSession() { - return this.session; - } - - public long getCreationTime() { - checkState(); - return this.session.getCreationTime(); - } - - public String getId() { - return this.session.getId(); - } - - public long getLastAccessedTime() { - checkState(); - return this.session.getLastAccessedTime(); - } - - public ServletContext getServletContext() { - return this.servletContext; - } - - public void setMaxInactiveInterval(int interval) { - this.session.setMaxInactiveIntervalInSeconds(interval); - } - - public int getMaxInactiveInterval() { - return this.session.getMaxInactiveIntervalInSeconds(); - } - - public HttpSessionContext getSessionContext() { - return NOOP_SESSION_CONTEXT; - } - - public Object getAttribute(String name) { - checkState(); - return this.session.getAttribute(name); - } - - public Object getValue(String name) { - return getAttribute(name); - } - - public Enumeration getAttributeNames() { - checkState(); - return Collections.enumeration(this.session.getAttributeNames()); - } - - public String[] getValueNames() { - checkState(); - Set attrs = this.session.getAttributeNames(); - return attrs.toArray(new String[0]); - } - - public void setAttribute(String name, Object value) { - checkState(); - this.session.setAttribute(name, value); - } - - public void putValue(String name, Object value) { - setAttribute(name, value); - } - - public void removeAttribute(String name) { - checkState(); - this.session.removeAttribute(name); - } - - public void removeValue(String name) { - removeAttribute(name); - } - - public void invalidate() { - checkState(); - this.invalidated = true; - } - - public void setNew(boolean isNew) { - this.old = !isNew; - } - - public boolean isNew() { - checkState(); - return !this.old; - } - - private void checkState() { - if (this.invalidated) { - throw new IllegalStateException( - "The HttpSession has already be invalidated."); - } - } - - private static final HttpSessionContext NOOP_SESSION_CONTEXT = new HttpSessionContext() { - public HttpSession getSession(String sessionId) { - return null; - } - - public Enumeration getIds() { - return EMPTY_ENUMERATION; - } - }; - - private static final Enumeration EMPTY_ENUMERATION = new Enumeration() { - public boolean hasMoreElements() { - return false; - } - - public String nextElement() { - throw new NoSuchElementException("a"); - } - }; -} diff --git a/spring-session/src/main/java/org/springframework/session/web/http/HeaderHttpSessionStrategy.java b/spring-session/src/main/java/org/springframework/session/web/http/HeaderHttpSessionStrategy.java deleted file mode 100644 index 4072c31..0000000 --- a/spring-session/src/main/java/org/springframework/session/web/http/HeaderHttpSessionStrategy.java +++ /dev/null @@ -1,86 +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.web.http; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.springframework.session.Session; -import org.springframework.util.Assert; - -/** - * A {@link HttpSessionStrategy} that uses a header to obtain the session from. - * Specifically, this implementation will allow specifying a header name using - * {@link HeaderHttpSessionStrategy#setHeaderName(String)}. The default is "X-Auth-Token". - * - * When a session is created, the HTTP response will have a response header of the - * specified name and the value of the session id. For example: - * - *
- * HTTP/1.1 200 OK
- * X-Auth-Token: f81d4fae-7dec-11d0-a765-00a0c91e6bf6
- * 
- * - * The client should now include the session in each request by specifying the same header - * in their request. For example: - * - *
- * GET /messages/ HTTP/1.1
- * Host: example.com
- * X-Auth-Token: f81d4fae-7dec-11d0-a765-00a0c91e6bf6
- * 
- * - * When the session is invalidated, the server will send an HTTP response that has the - * header name and a blank value. For example: - * - *
- * HTTP/1.1 200 OK
- * X-Auth-Token:
- * 
- * - * @author Rob Winch - * @since 1.0 - */ -public class HeaderHttpSessionStrategy implements HttpSessionStrategy { - - private String headerName = "X-Auth-Token"; - - public String getRequestedSessionId(HttpServletRequest request) { - return request.getHeader(this.headerName); - } - - public void onNewSession(Session session, HttpServletRequest request, - HttpServletResponse response) { - response.setHeader(this.headerName, session.getId()); - } - - public void onInvalidateSession(HttpServletRequest request, - HttpServletResponse response) { - response.setHeader(this.headerName, ""); - } - - /** - * The name of the header to obtain the session id from. Default is "X-Auth-Token". - * - * @param headerName the name of the header to obtain the session id from. - */ - public void setHeaderName(String headerName) { - Assert.notNull(headerName, "headerName cannot be null"); - this.headerName = headerName; - } - -} diff --git a/spring-session/src/main/java/org/springframework/session/web/http/HttpSessionManager.java b/spring-session/src/main/java/org/springframework/session/web/http/HttpSessionManager.java deleted file mode 100644 index 6f061a0..0000000 --- a/spring-session/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/src/main/java/org/springframework/session/web/http/HttpSessionStrategy.java b/spring-session/src/main/java/org/springframework/session/web/http/HttpSessionStrategy.java deleted file mode 100644 index 3c906d5..0000000 --- a/spring-session/src/main/java/org/springframework/session/web/http/HttpSessionStrategy.java +++ /dev/null @@ -1,79 +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; - -import org.springframework.session.Session; - -/** - * A strategy for mapping HTTP request and responses to a {@link Session}. - * - * @author Rob Winch - * @since 1.0 - */ -public interface HttpSessionStrategy { - - /** - * Obtains the requested session id from the provided - * {@link javax.servlet.http.HttpServletRequest}. For example, the session id might - * come from a cookie or a request header. - * - * @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. - */ - String getRequestedSessionId(HttpServletRequest request); - - /** - * This method is invoked when a new session is created and should inform a client - * what the new session id is. For example, it might create a new cookie with the - * session id in it or set an HTTP response header with the value of the new session - * id. - * - * Some implementations may wish to associate additional information to the - * {@link Session} at this time. For example, they may wish to add the IP Address, - * browser headers, the username, etc to the - * {@link org.springframework.session.Session}. - * - * @param session the {@link org.springframework.session.Session} that is being sent - * to the client. Cannot be null. - * @param request the {@link javax.servlet.http.HttpServletRequest} that create the - * new {@link org.springframework.session.Session} Cannot be null. - * @param response the {@link javax.servlet.http.HttpServletResponse} that is - * associated with the {@link javax.servlet.http.HttpServletRequest} that created the - * new {@link org.springframework.session.Session} Cannot be null. - */ - void onNewSession(Session session, HttpServletRequest request, - HttpServletResponse response); - - /** - * This method is invoked when a session is invalidated and should inform a client - * that the session id is no longer valid. For example, it might remove a cookie with - * the session id in it or set an HTTP response header with an empty value indicating - * to the client to no longer submit that session id. - * - * @param request the {@link javax.servlet.http.HttpServletRequest} that invalidated - * the {@link org.springframework.session.Session} Cannot be null. - * @param response the {@link javax.servlet.http.HttpServletResponse} that is - * associated with the {@link javax.servlet.http.HttpServletRequest} that invalidated - * the {@link org.springframework.session.Session} Cannot be null. - */ - void onInvalidateSession(HttpServletRequest request, HttpServletResponse response); -} diff --git a/spring-session/src/main/java/org/springframework/session/web/http/MultiHttpSessionStrategy.java b/spring-session/src/main/java/org/springframework/session/web/http/MultiHttpSessionStrategy.java deleted file mode 100644 index 8d297e9..0000000 --- a/spring-session/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/src/main/java/org/springframework/session/web/http/OnCommittedResponseWrapper.java b/spring-session/src/main/java/org/springframework/session/web/http/OnCommittedResponseWrapper.java deleted file mode 100644 index c584ccf..0000000 --- a/spring-session/src/main/java/org/springframework/session/web/http/OnCommittedResponseWrapper.java +++ /dev/null @@ -1,578 +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.io.IOException; -import java.io.PrintWriter; -import java.util.Locale; - -import javax.servlet.ServletOutputStream; -import javax.servlet.WriteListener; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpServletResponseWrapper; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * Base class for response wrappers which encapsulate the logic for handling an event when - * the {@link javax.servlet.http.HttpServletResponse} is committed. - * - * @author Rob Winch - * @since 1.0 - */ -abstract class OnCommittedResponseWrapper extends HttpServletResponseWrapper { - private final Log logger = LogFactory.getLog(getClass()); - - private boolean disableOnCommitted; - - /** - * The Content-Length response header. If this is greater than 0, then once - * {@link #contentWritten} is larger than or equal the response is considered - * committed. - */ - private long contentLength; - - /** - * The size of data written to the response body. - */ - private long contentWritten; - - /** - * Create a new {@link OnCommittedResponseWrapper}. - * @param response the response to be wrapped - */ - OnCommittedResponseWrapper(HttpServletResponse response) { - super(response); - } - - @Override - public void addHeader(String name, String value) { - if ("Content-Length".equalsIgnoreCase(name)) { - setContentLength(Long.parseLong(value)); - } - super.addHeader(name, value); - } - - @Override - public void setContentLength(int len) { - setContentLength((long) len); - super.setContentLength(len); - } - - private void setContentLength(long len) { - this.contentLength = len; - checkContentLength(0); - } - - /** - * Invoke this method to disable invoking - * {@link OnCommittedResponseWrapper#onResponseCommitted()} when the - * {@link javax.servlet.http.HttpServletResponse} is committed. This can be useful in - * the event that Async Web Requests are made. - */ - public void disableOnResponseCommitted() { - this.disableOnCommitted = true; - } - - /** - * Implement the logic for handling the {@link javax.servlet.http.HttpServletResponse} - * being committed. - */ - protected abstract void onResponseCommitted(); - - /** - * Makes sure {@link OnCommittedResponseWrapper#onResponseCommitted()} is invoked - * before calling the superclass sendError(). - * @param sc the error status code - */ - @Override - public final void sendError(int sc) throws IOException { - doOnResponseCommitted(); - super.sendError(sc); - } - - /** - * Makes sure {@link OnCommittedResponseWrapper#onResponseCommitted()} is invoked - * before calling the superclass sendError(). - * @param sc the error status code - */ - @Override - public final void sendError(int sc, String msg) throws IOException { - doOnResponseCommitted(); - super.sendError(sc, msg); - } - - /** - * Makes sure {@link OnCommittedResponseWrapper#onResponseCommitted()} is invoked - * before calling the superclass sendRedirect(). - * @param location the redirect URL location - */ - @Override - public final void sendRedirect(String location) throws IOException { - doOnResponseCommitted(); - super.sendRedirect(location); - } - - /** - * Makes sure {@link OnCommittedResponseWrapper#onResponseCommitted()} is invoked - * before calling the calling getOutputStream().close() or - * getOutputStream().flush(). - * @throws IOException if an input or output exception occurred - */ - @Override - public ServletOutputStream getOutputStream() throws IOException { - return new SaveContextServletOutputStream(super.getOutputStream()); - } - - /** - * Makes sure {@link OnCommittedResponseWrapper#onResponseCommitted()} is invoked - * before calling the getWriter().close() or - * getWriter().flush(). - * @throws IOException if an input or output exception occurred - */ - @Override - public PrintWriter getWriter() throws IOException { - return new SaveContextPrintWriter(super.getWriter()); - } - - /** - * Makes sure {@link OnCommittedResponseWrapper#onResponseCommitted()} is invoked - * before calling the superclass flushBuffer(). - * @throws IOException if an input or output exception occurred - */ - @Override - public void flushBuffer() throws IOException { - doOnResponseCommitted(); - super.flushBuffer(); - } - - private void trackContentLength(boolean content) { - checkContentLength(content ? 4 : 5); // TODO Localization - } - - private void trackContentLength(char content) { - checkContentLength(1); - } - - private void trackContentLength(Object content) { - trackContentLength(String.valueOf(content)); - } - - private void trackContentLength(byte[] content) { - checkContentLength(content == null ? 0 : content.length); - } - - private void trackContentLength(char[] content) { - checkContentLength(content == null ? 0 : content.length); - } - - private void trackContentLength(int content) { - trackContentLength(String.valueOf(content)); - } - - private void trackContentLength(float content) { - trackContentLength(String.valueOf(content)); - } - - private void trackContentLength(double content) { - trackContentLength(String.valueOf(content)); - } - - private void trackContentLengthLn() { - trackContentLength("\r\n"); - } - - private void trackContentLength(String content) { - checkContentLength(content.length()); - } - - /** - * Adds the contentLengthToWrite to the total contentWritten size and checks to see if - * the response should be written. - * - * @param contentLengthToWrite the size of the content that is about to be written. - */ - private void checkContentLength(long contentLengthToWrite) { - this.contentWritten += contentLengthToWrite; - boolean isBodyFullyWritten = this.contentLength > 0 - && this.contentWritten >= this.contentLength; - int bufferSize = getBufferSize(); - boolean requiresFlush = bufferSize > 0 && this.contentWritten >= bufferSize; - if (isBodyFullyWritten || requiresFlush) { - doOnResponseCommitted(); - } - } - - /** - * Calls onResponseCommmitted() with the current contents as long as - * {@link #disableOnResponseCommitted()} was not invoked. - */ - private void doOnResponseCommitted() { - if (!this.disableOnCommitted) { - onResponseCommitted(); - disableOnResponseCommitted(); - } - } - - /** - * Ensures {@link OnCommittedResponseWrapper#onResponseCommitted()} is invoked before - * calling the prior to methods that commit the response. We delegate all methods to - * the original {@link java.io.PrintWriter} to ensure that the behavior is as close to - * the original {@link java.io.PrintWriter} as possible. See SEC-2039 - * @author Rob Winch - */ - private class SaveContextPrintWriter extends PrintWriter { - private final PrintWriter delegate; - - SaveContextPrintWriter(PrintWriter delegate) { - super(delegate); - this.delegate = delegate; - } - - public void flush() { - doOnResponseCommitted(); - this.delegate.flush(); - } - - public void close() { - doOnResponseCommitted(); - this.delegate.close(); - } - - public int hashCode() { - return this.delegate.hashCode(); - } - - public boolean equals(Object obj) { - return this.delegate.equals(obj); - } - - public String toString() { - return getClass().getName() + "[delegate=" + this.delegate.toString() + "]"; - } - - public boolean checkError() { - return this.delegate.checkError(); - } - - public void write(int c) { - trackContentLength(c); - this.delegate.write(c); - } - - public void write(char[] buf, int off, int len) { - checkContentLength(len); - this.delegate.write(buf, off, len); - } - - public void write(char[] buf) { - trackContentLength(buf); - this.delegate.write(buf); - } - - public void write(String s, int off, int len) { - checkContentLength(len); - this.delegate.write(s, off, len); - } - - public void write(String s) { - trackContentLength(s); - this.delegate.write(s); - } - - public void print(boolean b) { - trackContentLength(b); - this.delegate.print(b); - } - - public void print(char c) { - trackContentLength(c); - this.delegate.print(c); - } - - public void print(int i) { - trackContentLength(i); - this.delegate.print(i); - } - - public void print(long l) { - trackContentLength(l); - this.delegate.print(l); - } - - public void print(float f) { - trackContentLength(f); - this.delegate.print(f); - } - - public void print(double d) { - trackContentLength(d); - this.delegate.print(d); - } - - public void print(char[] s) { - trackContentLength(s); - this.delegate.print(s); - } - - public void print(String s) { - trackContentLength(s); - this.delegate.print(s); - } - - public void print(Object obj) { - trackContentLength(obj); - this.delegate.print(obj); - } - - public void println() { - trackContentLengthLn(); - this.delegate.println(); - } - - public void println(boolean x) { - trackContentLength(x); - trackContentLengthLn(); - this.delegate.println(x); - } - - public void println(char x) { - trackContentLength(x); - trackContentLengthLn(); - this.delegate.println(x); - } - - public void println(int x) { - trackContentLength(x); - trackContentLengthLn(); - this.delegate.println(x); - } - - public void println(long x) { - trackContentLength(x); - trackContentLengthLn(); - this.delegate.println(x); - } - - public void println(float x) { - trackContentLength(x); - trackContentLengthLn(); - this.delegate.println(x); - } - - public void println(double x) { - trackContentLength(x); - trackContentLengthLn(); - this.delegate.println(x); - } - - public void println(char[] x) { - trackContentLength(x); - trackContentLengthLn(); - this.delegate.println(x); - } - - public void println(String x) { - trackContentLength(x); - trackContentLengthLn(); - this.delegate.println(x); - } - - public void println(Object x) { - trackContentLength(x); - trackContentLengthLn(); - this.delegate.println(x); - } - - public PrintWriter printf(String format, Object... args) { - return this.delegate.printf(format, args); - } - - public PrintWriter printf(Locale l, String format, Object... args) { - return this.delegate.printf(l, format, args); - } - - public PrintWriter format(String format, Object... args) { - return this.delegate.format(format, args); - } - - public PrintWriter format(Locale l, String format, Object... args) { - return this.delegate.format(l, format, args); - } - - public PrintWriter append(CharSequence csq) { - checkContentLength(csq.length()); - return this.delegate.append(csq); - } - - public PrintWriter append(CharSequence csq, int start, int end) { - checkContentLength(end - start); - return this.delegate.append(csq, start, end); - } - - public PrintWriter append(char c) { - trackContentLength(c); - return this.delegate.append(c); - } - } - - /** - * Ensures{@link OnCommittedResponseWrapper#onResponseCommitted()} is invoked before - * calling methods that commit the response. We delegate all methods to the original - * {@link javax.servlet.ServletOutputStream} to ensure that the behavior is as close - * to the original {@link javax.servlet.ServletOutputStream} as possible. See SEC-2039 - * - * @author Rob Winch - */ - private class SaveContextServletOutputStream extends ServletOutputStream { - private final ServletOutputStream delegate; - - SaveContextServletOutputStream(ServletOutputStream delegate) { - this.delegate = delegate; - } - - public void write(int b) throws IOException { - trackContentLength(b); - this.delegate.write(b); - } - - public void flush() throws IOException { - doOnResponseCommitted(); - this.delegate.flush(); - } - - public void close() throws IOException { - doOnResponseCommitted(); - this.delegate.close(); - } - - public int hashCode() { - return this.delegate.hashCode(); - } - - public boolean equals(Object obj) { - return this.delegate.equals(obj); - } - - public void print(boolean b) throws IOException { - trackContentLength(b); - this.delegate.print(b); - } - - public void print(char c) throws IOException { - trackContentLength(c); - this.delegate.print(c); - } - - public void print(double d) throws IOException { - trackContentLength(d); - this.delegate.print(d); - } - - public void print(float f) throws IOException { - trackContentLength(f); - this.delegate.print(f); - } - - public void print(int i) throws IOException { - trackContentLength(i); - this.delegate.print(i); - } - - public void print(long l) throws IOException { - trackContentLength(l); - this.delegate.print(l); - } - - public void print(String s) throws IOException { - trackContentLength(s); - this.delegate.print(s); - } - - public void println() throws IOException { - trackContentLengthLn(); - this.delegate.println(); - } - - public void println(boolean b) throws IOException { - trackContentLength(b); - trackContentLengthLn(); - this.delegate.println(b); - } - - public void println(char c) throws IOException { - trackContentLength(c); - trackContentLengthLn(); - this.delegate.println(c); - } - - public void println(double d) throws IOException { - trackContentLength(d); - trackContentLengthLn(); - this.delegate.println(d); - } - - public void println(float f) throws IOException { - trackContentLength(f); - trackContentLengthLn(); - this.delegate.println(f); - } - - public void println(int i) throws IOException { - trackContentLength(i); - trackContentLengthLn(); - this.delegate.println(i); - } - - public void println(long l) throws IOException { - trackContentLength(l); - trackContentLengthLn(); - this.delegate.println(l); - } - - public void println(String s) throws IOException { - trackContentLength(s); - trackContentLengthLn(); - this.delegate.println(s); - } - - public void write(byte[] b) throws IOException { - trackContentLength(b); - this.delegate.write(b); - } - - public void write(byte[] b, int off, int len) throws IOException { - checkContentLength(len); - this.delegate.write(b, off, len); - } - - public String toString() { - return getClass().getName() + "[delegate=" + this.delegate.toString() + "]"; - } - - @Override - public boolean isReady() { - return this.delegate.isReady(); - } - - @Override - public void setWriteListener(WriteListener writeListener) { - this.delegate.setWriteListener(writeListener); - } - } -} diff --git a/spring-session/src/main/java/org/springframework/session/web/http/OncePerRequestFilter.java b/spring-session/src/main/java/org/springframework/session/web/http/OncePerRequestFilter.java deleted file mode 100644 index 48f3ae9..0000000 --- a/spring-session/src/main/java/org/springframework/session/web/http/OncePerRequestFilter.java +++ /dev/null @@ -1,112 +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.io.IOException; - -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 javax.servlet.http.HttpServletResponse; - -/** - * Allows for easily ensuring that a request is only invoked once per request. This is a - * simplified version of spring-web's OncePerRequestFilter and copied to reduce the foot - * print required to use the session support. - * - * @author Rob Winch - * @since 1.0 - */ -abstract class OncePerRequestFilter implements Filter { - /** - * Suffix that gets appended to the filter name for the "already filtered" request - * attribute. - */ - public static final String ALREADY_FILTERED_SUFFIX = ".FILTERED"; - - private String alreadyFilteredAttributeName = getClass().getName() - .concat(ALREADY_FILTERED_SUFFIX); - - /** - * This {@code doFilter} implementation stores a request attribute for - * "already filtered", proceeding without filtering again if the attribute is already - * there. - * @param request the request - * @param response the response - * @param filterChain the filter chain - * @throws ServletException if request is not HTTP request - * @throws IOException in case of I/O operation exception - */ - public final void doFilter(ServletRequest request, ServletResponse response, - FilterChain filterChain) throws ServletException, IOException { - - if (!(request instanceof HttpServletRequest) - || !(response instanceof HttpServletResponse)) { - throw new ServletException( - "OncePerRequestFilter just supports HTTP requests"); - } - HttpServletRequest httpRequest = (HttpServletRequest) request; - HttpServletResponse httpResponse = (HttpServletResponse) response; - boolean hasAlreadyFilteredAttribute = request - .getAttribute(this.alreadyFilteredAttributeName) != null; - - if (hasAlreadyFilteredAttribute) { - - // Proceed without invoking this filter... - filterChain.doFilter(request, response); - } - else { - // Do invoke this filter... - request.setAttribute(this.alreadyFilteredAttributeName, Boolean.TRUE); - try { - doFilterInternal(httpRequest, httpResponse, filterChain); - } - finally { - // Remove the "already filtered" request attribute for this request. - request.removeAttribute(this.alreadyFilteredAttributeName); - } - } - } - - /** - * Same contract as for {@code doFilter}, but guaranteed to be just invoked once per - * request within a single request thread. - *

- * Provides HttpServletRequest and HttpServletResponse arguments instead of the - * default ServletRequest and ServletResponse ones. - * - * @param request the request - * @param response the response - * @param filterChain the FilterChain - * @throws ServletException thrown when a non-I/O exception has occurred - * @throws IOException thrown when an I/O exception of some sort has occurred - * @see Filter#doFilter - */ - protected abstract void doFilterInternal(HttpServletRequest request, - HttpServletResponse response, FilterChain filterChain) - throws ServletException, IOException; - - public void init(FilterConfig config) { - } - - public void destroy() { - } -} diff --git a/spring-session/src/main/java/org/springframework/session/web/http/RequestResponsePostProcessor.java b/spring-session/src/main/java/org/springframework/session/web/http/RequestResponsePostProcessor.java deleted file mode 100644 index efe3bba..0000000 --- a/spring-session/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/src/main/java/org/springframework/session/web/http/SessionEventHttpSessionListenerAdapter.java b/spring-session/src/main/java/org/springframework/session/web/http/SessionEventHttpSessionListenerAdapter.java deleted file mode 100644 index bda6c8d..0000000 --- a/spring-session/src/main/java/org/springframework/session/web/http/SessionEventHttpSessionListenerAdapter.java +++ /dev/null @@ -1,93 +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.List; - -import javax.servlet.ServletContext; -import javax.servlet.http.HttpSession; -import javax.servlet.http.HttpSessionEvent; -import javax.servlet.http.HttpSessionListener; - -import org.springframework.context.ApplicationListener; -import org.springframework.session.ExpiringSession; -import org.springframework.session.events.AbstractSessionEvent; -import org.springframework.session.events.SessionCreatedEvent; -import org.springframework.session.events.SessionDestroyedEvent; -import org.springframework.web.context.ServletContextAware; - -/** - * Receives {@link SessionDestroyedEvent} and {@link SessionCreatedEvent} and translates - * them into {@link HttpSessionEvent} and submits the {@link HttpSessionEvent} to every - * registered {@link HttpSessionListener}. - * - * @author Rob Winch - * @since 1.1 - */ -public class SessionEventHttpSessionListenerAdapter - implements ApplicationListener, ServletContextAware { - private final List listeners; - - private ServletContext context; - - public SessionEventHttpSessionListenerAdapter(List listeners) { - super(); - this.listeners = listeners; - } - - /* - * (non-Javadoc) - * - * @see org.springframework.context.ApplicationListener#onApplicationEvent(org. - * springframework.context.ApplicationEvent) - */ - public void onApplicationEvent(AbstractSessionEvent event) { - if (this.listeners.isEmpty()) { - return; - } - - HttpSessionEvent httpSessionEvent = createHttpSessionEvent(event); - - for (HttpSessionListener listener : this.listeners) { - if (event instanceof SessionDestroyedEvent) { - listener.sessionDestroyed(httpSessionEvent); - } - else if (event instanceof SessionCreatedEvent) { - listener.sessionCreated(httpSessionEvent); - } - } - } - - private HttpSessionEvent createHttpSessionEvent(AbstractSessionEvent event) { - ExpiringSession session = event.getSession(); - HttpSession httpSession = new ExpiringSessionHttpSession(session, - this.context); - HttpSessionEvent httpSessionEvent = new HttpSessionEvent(httpSession); - return httpSessionEvent; - } - - /* - * (non-Javadoc) - * - * @see - * org.springframework.web.context.ServletContextAware#setServletContext(javax.servlet - * .ServletContext) - */ - public void setServletContext(ServletContext servletContext) { - this.context = servletContext; - } -} diff --git a/spring-session/src/main/java/org/springframework/session/web/http/SessionRepositoryFilter.java b/spring-session/src/main/java/org/springframework/session/web/http/SessionRepositoryFilter.java deleted file mode 100644 index 180a928..0000000 --- a/spring-session/src/main/java/org/springframework/session/web/http/SessionRepositoryFilter.java +++ /dev/null @@ -1,459 +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.io.IOException; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.Map; - -import javax.servlet.FilterChain; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletRequestWrapper; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.core.annotation.Order; -import org.springframework.session.ExpiringSession; -import org.springframework.session.Session; -import org.springframework.session.SessionRepository; - -/** - * Switches the {@link javax.servlet.http.HttpSession} implementation to be backed by a - * {@link org.springframework.session.Session}. - * - * The {@link SessionRepositoryFilter} wraps the - * {@link javax.servlet.http.HttpServletRequest} and overrides the methods to get an - * {@link javax.servlet.http.HttpSession} to be backed by a - * {@link org.springframework.session.Session} returned by the - * {@link org.springframework.session.SessionRepository}. - * - * The {@link SessionRepositoryFilter} uses a {@link HttpSessionStrategy} (default - * {@link CookieHttpSessionStrategy} to bridge logic between an - * {@link javax.servlet.http.HttpSession} and the - * {@link org.springframework.session.Session} abstraction. Specifically: - * - *

    - *
  • The session id is looked up using - * {@link HttpSessionStrategy#getRequestedSessionId(javax.servlet.http.HttpServletRequest)} - * . The default is to look in a cookie named SESSION.
  • - *
  • The session id of newly created {@link org.springframework.session.ExpiringSession} - * 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)} - *
  • - *
- * - *

- * The SessionRepositoryFilter must be placed before any Filter that access the - * HttpSession or that might commit the response to ensure the session is overridden and - * persisted properly. - *

- * - * @param the {@link ExpiringSession} type. - * @since 1.0 - * @author Rob Winch - */ -@Order(SessionRepositoryFilter.DEFAULT_ORDER) -public class SessionRepositoryFilter - extends OncePerRequestFilter { - private static final String SESSION_LOGGER_NAME = SessionRepositoryFilter.class - .getName().concat(".SESSION_LOGGER"); - - private static final Log SESSION_LOGGER = LogFactory.getLog(SESSION_LOGGER_NAME); - - /** - * The session repository request attribute name. - */ - public static final String SESSION_REPOSITORY_ATTR = SessionRepository.class - .getName(); - - /** - * Invalid session id (not backed by the session repository) request attribute name. - */ - public static final String INVALID_SESSION_ID_ATTR = SESSION_REPOSITORY_ATTR - + ".invalidSessionId"; - - private static final String CURRENT_SESSION_ATTR = SESSION_REPOSITORY_ATTR - + ".CURRENT_SESSION"; - - /** - * The default filter order. - */ - public static final int DEFAULT_ORDER = Integer.MIN_VALUE + 50; - - private final SessionRepository sessionRepository; - - private ServletContext servletContext; - - private MultiHttpSessionStrategy httpSessionStrategy = new CookieHttpSessionStrategy(); - - /** - * Creates a new instance. - * - * @param sessionRepository the SessionRepository to use. Cannot be null. - */ - public SessionRepositoryFilter(SessionRepository sessionRepository) { - if (sessionRepository == null) { - throw new IllegalArgumentException("sessionRepository cannot be null"); - } - this.sessionRepository = sessionRepository; - } - - /** - * Sets the {@link HttpSessionStrategy} to be used. The default is a - * {@link CookieHttpSessionStrategy}. - * - * @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"); - } - this.httpSessionStrategy = httpSessionStrategy; - } - - @Override - protected void doFilterInternal(HttpServletRequest request, - HttpServletResponse response, FilterChain filterChain) - throws ServletException, IOException { - request.setAttribute(SESSION_REPOSITORY_ATTR, this.sessionRepository); - - SessionRepositoryRequestWrapper wrappedRequest = new SessionRepositoryRequestWrapper( - request, response, this.servletContext); - 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); - } - finally { - wrappedRequest.commitSession(); - } - } - - public void setServletContext(ServletContext servletContext) { - this.servletContext = servletContext; - } - - /** - * Allows ensuring that the session is saved if the response is committed. - * - * @author Rob Winch - * @since 1.0 - */ - private final class SessionRepositoryResponseWrapper - extends OnCommittedResponseWrapper { - - private final SessionRepositoryRequestWrapper request; - - /** - * Create a new {@link SessionRepositoryResponseWrapper}. - * @param request the request to be wrapped - * @param response the response to be wrapped - */ - SessionRepositoryResponseWrapper(SessionRepositoryRequestWrapper request, - HttpServletResponse response) { - super(response); - if (request == null) { - throw new IllegalArgumentException("request cannot be null"); - } - this.request = request; - } - - @Override - protected void onResponseCommitted() { - this.request.commitSession(); - } - } - - /** - * A {@link javax.servlet.http.HttpServletRequest} that retrieves the - * {@link javax.servlet.http.HttpSession} using a - * {@link org.springframework.session.SessionRepository}. - * - * @author Rob Winch - * @since 1.0 - */ - private final class SessionRepositoryRequestWrapper - extends HttpServletRequestWrapper { - private Boolean requestedSessionIdValid; - private boolean requestedSessionInvalidated; - private final HttpServletResponse response; - private final ServletContext servletContext; - - private SessionRepositoryRequestWrapper(HttpServletRequest request, - HttpServletResponse response, ServletContext servletContext) { - super(request); - this.response = response; - this.servletContext = servletContext; - } - - /** - * Uses the HttpSessionStrategy to write the session id to the response and - * persist the Session. - */ - private void commitSession() { - HttpSessionWrapper wrappedSession = getCurrentSession(); - if (wrappedSession == null) { - if (isInvalidateClientSession()) { - SessionRepositoryFilter.this.httpSessionStrategy - .onInvalidateSession(this, this.response); - } - } - else { - S session = wrappedSession.getSession(); - SessionRepositoryFilter.this.sessionRepository.save(session); - if (!isRequestedSessionIdValid() - || !session.getId().equals(getRequestedSessionId())) { - SessionRepositoryFilter.this.httpSessionStrategy.onNewSession(session, - this, this.response); - } - } - } - - @SuppressWarnings("unchecked") - private HttpSessionWrapper getCurrentSession() { - return (HttpSessionWrapper) getAttribute(CURRENT_SESSION_ATTR); - } - - private void setCurrentSession(HttpSessionWrapper currentSession) { - if (currentSession == null) { - removeAttribute(CURRENT_SESSION_ATTR); - } - else { - setAttribute(CURRENT_SESSION_ATTR, currentSession); - } - } - - @SuppressWarnings("unused") - public String changeSessionId() { - HttpSession session = getSession(false); - - if (session == null) { - throw new IllegalStateException( - "Cannot change session ID. There is no session associated with this request."); - } - - // eagerly get session attributes in case implementation lazily loads them - Map attrs = new HashMap(); - Enumeration iAttrNames = session.getAttributeNames(); - while (iAttrNames.hasMoreElements()) { - String attrName = iAttrNames.nextElement(); - Object value = session.getAttribute(attrName); - - attrs.put(attrName, value); - } - - SessionRepositoryFilter.this.sessionRepository.delete(session.getId()); - HttpSessionWrapper original = getCurrentSession(); - setCurrentSession(null); - - HttpSessionWrapper newSession = getSession(); - original.setSession(newSession.getSession()); - - newSession.setMaxInactiveInterval(session.getMaxInactiveInterval()); - for (Map.Entry attr : attrs.entrySet()) { - String attrName = attr.getKey(); - Object attrValue = attr.getValue(); - newSession.setAttribute(attrName, attrValue); - } - return newSession.getId(); - } - - @Override - public boolean isRequestedSessionIdValid() { - if (this.requestedSessionIdValid == null) { - String sessionId = getRequestedSessionId(); - S session = sessionId == null ? null : getSession(sessionId); - return isRequestedSessionIdValid(session); - } - - return this.requestedSessionIdValid; - } - - private boolean isRequestedSessionIdValid(S session) { - if (this.requestedSessionIdValid == null) { - this.requestedSessionIdValid = session != null; - } - return this.requestedSessionIdValid; - } - - private boolean isInvalidateClientSession() { - return getCurrentSession() == null && this.requestedSessionInvalidated; - } - - private S getSession(String sessionId) { - S session = SessionRepositoryFilter.this.sessionRepository - .getSession(sessionId); - if (session == null) { - return null; - } - session.setLastAccessedTime(System.currentTimeMillis()); - return session; - } - - @Override - public HttpSessionWrapper getSession(boolean create) { - HttpSessionWrapper currentSession = getCurrentSession(); - if (currentSession != null) { - return currentSession; - } - String requestedSessionId = getRequestedSessionId(); - if (requestedSessionId != null - && getAttribute(INVALID_SESSION_ID_ATTR) == null) { - S session = getSession(requestedSessionId); - if (session != null) { - 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"); - } - } - if (!create) { - return null; - } - if (SESSION_LOGGER.isDebugEnabled()) { - SESSION_LOGGER.debug( - "A new session was created. To help you troubleshoot where the session was created we provided a StackTrace (this is not an error). You can prevent this from appearing by disabling DEBUG logging for " - + SESSION_LOGGER_NAME, - new RuntimeException( - "For debugging purposes only (not an error)")); - } - S session = SessionRepositoryFilter.this.sessionRepository.createSession(); - session.setLastAccessedTime(System.currentTimeMillis()); - currentSession = new HttpSessionWrapper(session, getServletContext()); - setCurrentSession(currentSession); - return currentSession; - } - - @Override - public ServletContext getServletContext() { - if (this.servletContext != null) { - return this.servletContext; - } - // Servlet 3.0+ - return super.getServletContext(); - } - - @Override - public HttpSessionWrapper getSession() { - return getSession(true); - } - - @Override - public String getRequestedSessionId() { - return SessionRepositoryFilter.this.httpSessionStrategy - .getRequestedSessionId(this); - } - - /** - * Allows creating an HttpSession from a Session instance. - * - * @author Rob Winch - * @since 1.0 - */ - private final class HttpSessionWrapper extends ExpiringSessionHttpSession { - - HttpSessionWrapper(S session, ServletContext servletContext) { - super(session, servletContext); - } - - @Override - public void invalidate() { - super.invalidate(); - SessionRepositoryRequestWrapper.this.requestedSessionInvalidated = true; - setCurrentSession(null); - SessionRepositoryFilter.this.sessionRepository.delete(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/src/main/java/org/springframework/session/web/socket/config/annotation/AbstractSessionWebSocketMessageBrokerConfigurer.java b/spring-session/src/main/java/org/springframework/session/web/socket/config/annotation/AbstractSessionWebSocketMessageBrokerConfigurer.java deleted file mode 100644 index 1b569e7..0000000 --- a/spring-session/src/main/java/org/springframework/session/web/socket/config/annotation/AbstractSessionWebSocketMessageBrokerConfigurer.java +++ /dev/null @@ -1,165 +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.socket.config.annotation; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationEventPublisher; -import org.springframework.context.annotation.Bean; -import org.springframework.messaging.simp.config.ChannelRegistration; -import org.springframework.session.ExpiringSession; -import org.springframework.session.Session; -import org.springframework.session.SessionRepository; -import org.springframework.session.web.socket.handler.WebSocketConnectHandlerDecoratorFactory; -import org.springframework.session.web.socket.handler.WebSocketRegistryListener; -import org.springframework.session.web.socket.server.SessionRepositoryMessageInterceptor; -import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer; -import org.springframework.web.socket.config.annotation.StompEndpointRegistry; -import org.springframework.web.socket.config.annotation.StompWebSocketEndpointRegistration; -import org.springframework.web.socket.config.annotation.WebMvcStompEndpointRegistry; -import org.springframework.web.socket.config.annotation.WebSocketTransportRegistration; -import org.springframework.web.socket.messaging.StompSubProtocolErrorHandler; -import org.springframework.web.socket.server.HandshakeInterceptor; -import org.springframework.web.util.UrlPathHelper; - -/** - * Eases configuration of Web Socket and Spring Session integration. - * - *

- * The configuration: - *

- *
    - *
  • Ensures the {@link Session} is kept alive on incoming web socket messages.
  • - *
  • Ensures that Web Socket Sessions are destroyed when a {@link Session} is terminated - *
  • - *
- * - *

- * Example usage - *

- * - * - * {@literal @Configuration} - * {@literal @EnableScheduling} - * {@literal @EnableWebSocketMessageBroker} - * {@literal public class WebSocketConfig extends AbstractSessionWebSocketMessageBrokerConfigurer} { - * - * {@literal @Override} - * protected void configureStompEndpoints(StompEndpointRegistry registry) { - * registry.addEndpoint("/messages") - * .withSockJS(); - * } - * - * {@literal @Override} - * public void configureMessageBroker(MessageBrokerRegistry registry) { - * registry.enableSimpleBroker("/queue/", "/topic/"); - * registry.setApplicationDestinationPrefixes("/app"); - * } - * } - * - * - * @param the type of ExpiringSession - * @author Rob Winch - * @since 1.0 - */ -public abstract class AbstractSessionWebSocketMessageBrokerConfigurer - extends AbstractWebSocketMessageBrokerConfigurer { - - @Autowired - @SuppressWarnings("rawtypes") - private SessionRepository sessionRepository; - - @Autowired - private ApplicationEventPublisher eventPublisher; - - @Override - public void configureClientInboundChannel(ChannelRegistration registration) { - registration.setInterceptors(sessionRepositoryInterceptor()); - } - - public final void registerStompEndpoints(StompEndpointRegistry registry) { - if (registry instanceof WebMvcStompEndpointRegistry) { - WebMvcStompEndpointRegistry mvcRegistry = (WebMvcStompEndpointRegistry) registry; - configureStompEndpoints(new SessionStompEndpointRegistry(mvcRegistry, - sessionRepositoryInterceptor())); - } - } - - /** - * Register STOMP endpoints mapping each to a specific URL and (optionally) enabling - * and configuring SockJS fallback options with a - * {@link SessionRepositoryMessageInterceptor} automatically added as an interceptor. - * - * @param registry the {@link StompEndpointRegistry} which automatically has a - * {@link SessionRepositoryMessageInterceptor} added to it. - */ - protected abstract void configureStompEndpoints(StompEndpointRegistry registry); - - @Override - public void configureWebSocketTransport(WebSocketTransportRegistration registration) { - registration.addDecoratorFactory(wsConnectHandlerDecoratorFactory()); - } - - @Bean - public WebSocketRegistryListener webSocketRegistryListener() { - return new WebSocketRegistryListener(); - } - - @Bean - public WebSocketConnectHandlerDecoratorFactory wsConnectHandlerDecoratorFactory() { - return new WebSocketConnectHandlerDecoratorFactory(this.eventPublisher); - } - - @Bean - @SuppressWarnings("unchecked") - public SessionRepositoryMessageInterceptor sessionRepositoryInterceptor() { - return new SessionRepositoryMessageInterceptor(this.sessionRepository); - } - - /** - * A {@link StompEndpointRegistry} that applies {@link HandshakeInterceptor}. - */ - static class SessionStompEndpointRegistry implements StompEndpointRegistry { - private final WebMvcStompEndpointRegistry registry; - private final HandshakeInterceptor interceptor; - - SessionStompEndpointRegistry(WebMvcStompEndpointRegistry registry, - HandshakeInterceptor interceptor) { - this.registry = registry; - this.interceptor = interceptor; - } - - public StompWebSocketEndpointRegistration addEndpoint(String... paths) { - StompWebSocketEndpointRegistration endpoints = this.registry - .addEndpoint(paths); - endpoints.addInterceptors(this.interceptor); - return endpoints; - } - - public void setOrder(int order) { - this.registry.setOrder(order); - } - - public void setUrlPathHelper(UrlPathHelper urlPathHelper) { - this.registry.setUrlPathHelper(urlPathHelper); - } - - public WebMvcStompEndpointRegistry setErrorHandler( - StompSubProtocolErrorHandler errorHandler) { - return this.registry.setErrorHandler(errorHandler); - } - } -} diff --git a/spring-session/src/main/java/org/springframework/session/web/socket/events/SessionConnectEvent.java b/spring-session/src/main/java/org/springframework/session/web/socket/events/SessionConnectEvent.java deleted file mode 100644 index ba51f8f..0000000 --- a/spring-session/src/main/java/org/springframework/session/web/socket/events/SessionConnectEvent.java +++ /dev/null @@ -1,47 +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.socket.events; - -import org.springframework.context.ApplicationEvent; -import org.springframework.session.web.socket.handler.WebSocketConnectHandlerDecoratorFactory; -import org.springframework.session.web.socket.handler.WebSocketRegistryListener; -import org.springframework.web.socket.WebSocketSession; - -/** - * Similar to Spring {@link org.springframework.web.socket.messaging.SessionConnectEvent} - * except that it provides access to the {@link WebSocketSession} to allow mapping the - * Spring Session to the {@link WebSocketSession}. - * - * @author Rob Winch - * @since 1.0 - * @see WebSocketRegistryListener - * @see WebSocketConnectHandlerDecoratorFactory - */ -@SuppressWarnings("serial") -public class SessionConnectEvent extends ApplicationEvent { - - private final WebSocketSession webSocketSession; - - public SessionConnectEvent(Object source, WebSocketSession webSocketSession) { - super(source); - this.webSocketSession = webSocketSession; - } - - public WebSocketSession getWebSocketSession() { - return this.webSocketSession; - } -} diff --git a/spring-session/src/main/java/org/springframework/session/web/socket/handler/WebSocketConnectHandlerDecoratorFactory.java b/spring-session/src/main/java/org/springframework/session/web/socket/handler/WebSocketConnectHandlerDecoratorFactory.java deleted file mode 100644 index 1e22abc..0000000 --- a/spring-session/src/main/java/org/springframework/session/web/socket/handler/WebSocketConnectHandlerDecoratorFactory.java +++ /dev/null @@ -1,91 +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.socket.handler; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.context.ApplicationEvent; -import org.springframework.context.ApplicationEventPublisher; -import org.springframework.session.Session; -import org.springframework.session.web.socket.events.SessionConnectEvent; -import org.springframework.util.Assert; -import org.springframework.web.socket.WebSocketHandler; -import org.springframework.web.socket.WebSocketSession; -import org.springframework.web.socket.handler.WebSocketHandlerDecorator; -import org.springframework.web.socket.handler.WebSocketHandlerDecoratorFactory; - -/** - * Ensures that a {@link SessionConnectEvent} is published in - * {@link WebSocketHandler#afterConnectionEstablished(WebSocketSession)}. This is - * necessary so that the {@link WebSocketSession} can be mapped to the corresponding - * Spring {@link Session} to terminate any {@link WebSocketSession} associated with a - * Spring {@link Session} that was destroyed. - * - * @author Rob Winch - * @since 1.0 - * - * @see WebSocketRegistryListener - */ -public final class WebSocketConnectHandlerDecoratorFactory - implements WebSocketHandlerDecoratorFactory { - - private static final Log logger = LogFactory - .getLog(WebSocketConnectHandlerDecoratorFactory.class); - - private final ApplicationEventPublisher eventPublisher; - - /** - * Creates a new instance. - * - * @param eventPublisher the {@link ApplicationEventPublisher} to use. Cannot be null. - */ - public WebSocketConnectHandlerDecoratorFactory( - ApplicationEventPublisher eventPublisher) { - Assert.notNull(eventPublisher, "eventPublisher cannot be null"); - this.eventPublisher = eventPublisher; - } - - public WebSocketHandler decorate(WebSocketHandler handler) { - return new SessionWebSocketHandler(handler); - } - - private final class SessionWebSocketHandler extends WebSocketHandlerDecorator { - - SessionWebSocketHandler(WebSocketHandler delegate) { - super(delegate); - } - - @Override - public void afterConnectionEstablished(WebSocketSession wsSession) - throws Exception { - super.afterConnectionEstablished(wsSession); - - publishEvent(new SessionConnectEvent(this, wsSession)); - } - - private void publishEvent(ApplicationEvent event) { - try { - WebSocketConnectHandlerDecoratorFactory.this.eventPublisher - .publishEvent(event); - } - catch (Throwable ex) { - logger.error("Error publishing " + event + ".", ex); - } - } - } -} diff --git a/spring-session/src/main/java/org/springframework/session/web/socket/handler/WebSocketRegistryListener.java b/spring-session/src/main/java/org/springframework/session/web/socket/handler/WebSocketRegistryListener.java deleted file mode 100644 index ce36b38..0000000 --- a/spring-session/src/main/java/org/springframework/session/web/socket/handler/WebSocketRegistryListener.java +++ /dev/null @@ -1,149 +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.socket.handler; - -import java.io.IOException; -import java.security.Principal; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.context.ApplicationEvent; -import org.springframework.context.ApplicationListener; -import org.springframework.messaging.simp.SimpMessageHeaderAccessor; -import org.springframework.session.events.SessionDestroyedEvent; -import org.springframework.session.web.socket.events.SessionConnectEvent; -import org.springframework.session.web.socket.server.SessionRepositoryMessageInterceptor; -import org.springframework.web.socket.CloseStatus; -import org.springframework.web.socket.WebSocketSession; -import org.springframework.web.socket.messaging.SessionDisconnectEvent; - -/** - *

- * Keeps track of mapping the Spring Session ID to the {@link WebSocketSession} and - * ensuring when a {@link SessionDestroyedEvent} is fired that the - * {@link WebSocketSession} is closed. - *

- * - * - * @author Rob Winch - * @author Mark Anderson - * @since 1.0 - */ -public final class WebSocketRegistryListener - implements ApplicationListener { - - private static final Log logger = LogFactory.getLog(WebSocketRegistryListener.class); - - static final CloseStatus SESSION_EXPIRED_STATUS = new CloseStatus( - CloseStatus.POLICY_VIOLATION.getCode(), - "This connection was established under an authenticated HTTP Session that has expired"); - - private final ConcurrentHashMap> httpSessionIdToWsSessions = new ConcurrentHashMap>(); - - public void onApplicationEvent(ApplicationEvent event) { - if (event instanceof SessionDestroyedEvent) { - SessionDestroyedEvent e = (SessionDestroyedEvent) event; - closeWsSessions(e.getSessionId()); - } - else if (event instanceof SessionConnectEvent) { - SessionConnectEvent e = (SessionConnectEvent) event; - afterConnectionEstablished(e.getWebSocketSession()); - } - else if (event instanceof SessionDisconnectEvent) { - SessionDisconnectEvent e = (SessionDisconnectEvent) event; - Map sessionAttributes = SimpMessageHeaderAccessor - .getSessionAttributes(e.getMessage().getHeaders()); - String httpSessionId = sessionAttributes == null ? null - : SessionRepositoryMessageInterceptor.getSessionId(sessionAttributes); - afterConnectionClosed(httpSessionId, e.getSessionId()); - } - } - - private void afterConnectionEstablished(WebSocketSession wsSession) { - Principal principal = wsSession.getPrincipal(); - if (principal == null) { - return; - } - - String httpSessionId = getHttpSessionId(wsSession); - registerWsSession(httpSessionId, wsSession); - } - - private String getHttpSessionId(WebSocketSession wsSession) { - Map attributes = wsSession.getAttributes(); - return SessionRepositoryMessageInterceptor.getSessionId(attributes); - } - - private void afterConnectionClosed(String httpSessionId, String wsSessionId) { - if (httpSessionId == null) { - return; - } - - Map sessions = this.httpSessionIdToWsSessions - .get(httpSessionId); - if (sessions != null) { - boolean result = sessions.remove(wsSessionId) != null; - if (logger.isDebugEnabled()) { - logger.debug("Removal of " + wsSessionId + " was " + result); - } - if (sessions.isEmpty()) { - this.httpSessionIdToWsSessions.remove(httpSessionId); - if (logger.isDebugEnabled()) { - logger.debug("Removed the corresponding HTTP Session for " - + wsSessionId + " since it contained no WebSocket mappings"); - } - } - } - } - - private void registerWsSession(String httpSessionId, WebSocketSession wsSession) { - Map sessions = this.httpSessionIdToWsSessions - .get(httpSessionId); - if (sessions == null) { - sessions = new ConcurrentHashMap(); - this.httpSessionIdToWsSessions.putIfAbsent(httpSessionId, sessions); - sessions = this.httpSessionIdToWsSessions.get(httpSessionId); - } - sessions.put(wsSession.getId(), wsSession); - } - - private void closeWsSessions(String httpSessionId) { - Map sessionsToClose = this.httpSessionIdToWsSessions - .remove(httpSessionId); - if (sessionsToClose == null) { - return; - } - if (logger.isDebugEnabled()) { - logger.debug( - "Closing WebSocket connections associated to expired HTTP Session " - + httpSessionId); - } - for (WebSocketSession toClose : sessionsToClose.values()) { - try { - toClose.close(SESSION_EXPIRED_STATUS); - } - catch (IOException e) { - logger.debug( - "Failed to close WebSocketSession (this is nothing to worry about but for debugging only)", - e); - } - } - } -} diff --git a/spring-session/src/main/java/org/springframework/session/web/socket/server/SessionRepositoryMessageInterceptor.java b/spring-session/src/main/java/org/springframework/session/web/socket/server/SessionRepositoryMessageInterceptor.java deleted file mode 100644 index 9da32b0..0000000 --- a/spring-session/src/main/java/org/springframework/session/web/socket/server/SessionRepositoryMessageInterceptor.java +++ /dev/null @@ -1,157 +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.socket.server; - -import java.util.EnumSet; -import java.util.Map; -import java.util.Set; - -import javax.servlet.http.HttpSession; - -import org.springframework.http.server.ServerHttpRequest; -import org.springframework.http.server.ServerHttpResponse; -import org.springframework.http.server.ServletServerHttpRequest; -import org.springframework.messaging.Message; -import org.springframework.messaging.MessageChannel; -import org.springframework.messaging.simp.SimpMessageHeaderAccessor; -import org.springframework.messaging.simp.SimpMessageType; -import org.springframework.messaging.support.ChannelInterceptor; -import org.springframework.messaging.support.ChannelInterceptorAdapter; -import org.springframework.session.ExpiringSession; -import org.springframework.session.Session; -import org.springframework.session.SessionRepository; -import org.springframework.util.Assert; -import org.springframework.web.socket.WebSocketHandler; -import org.springframework.web.socket.server.HandshakeInterceptor; - -/** - *

- * Acts as a {@link ChannelInterceptor} and a {@link HandshakeInterceptor} to ensure the - * {@link ExpiringSession#getLastAccessedTime()} is up to date. - *

- *
    - *
  • Associates the {@link Session#getId()} with the WebSocket Session attributes when - * the handshake is performed. This is later used when intercepting messages to ensure the - * {@link ExpiringSession#getLastAccessedTime()} is updated.
  • - *
  • Intercepts {@link Message}'s that are have {@link SimpMessageType} that corresponds - * to {@link #setMatchingMessageTypes(Set)} and updates the last accessed time of the - * {@link Session}. If the {@link Session} is expired, the {@link Message} is prevented - * from proceeding.
  • - *
- * - *

- * In order to work {@link SessionRepositoryMessageInterceptor} must be registered as a - * {@link ChannelInterceptor} and a {@link HandshakeInterceptor} . - *

- * - * @param the {@link ExpiringSession} type - * @author Rob Winch - * @since 1.0 - */ -public final class SessionRepositoryMessageInterceptor - extends ChannelInterceptorAdapter implements HandshakeInterceptor { - - private static final String SPRING_SESSION_ID_ATTR_NAME = "SPRING.SESSION.ID"; - - private final SessionRepository sessionRepository; - - private Set matchingMessageTypes; - - /** - * Creates a new instance. - * - * @param sessionRepository the {@link SessionRepository} to use. Cannot be null. - */ - public SessionRepositoryMessageInterceptor(SessionRepository sessionRepository) { - Assert.notNull(sessionRepository, "sessionRepository cannot be null"); - this.sessionRepository = sessionRepository; - this.matchingMessageTypes = EnumSet.of(SimpMessageType.CONNECT, - SimpMessageType.MESSAGE, SimpMessageType.SUBSCRIBE, - SimpMessageType.UNSUBSCRIBE); - } - - /** - *

- * Sets the {@link SimpMessageType} to match on. If the {@link Message} matches, then - * {@link #preSend(Message, MessageChannel)} ensures the {@link Session} is not - * expired and updates the {@link ExpiringSession#getLastAccessedTime()} - *

- * - *

- * The default is: SimpMessageType.CONNECT, SimpMessageType.MESSAGE, - * SimpMessageType.SUBSCRIBE, SimpMessageType.UNSUBSCRIBE. - *

- * - * @param matchingMessageTypes the {@link SimpMessageType} to match on in - * {@link #preSend(Message, MessageChannel)}, else the {@link Message} is continued - * without accessing or updating the {@link Session} - */ - public void setMatchingMessageTypes(Set matchingMessageTypes) { - Assert.notEmpty(matchingMessageTypes, - "matchingMessageTypes cannot be null or empty"); - this.matchingMessageTypes = matchingMessageTypes; - } - - @Override - public Message preSend(Message message, MessageChannel channel) { - if (message == null) { - return message; - } - SimpMessageType messageType = SimpMessageHeaderAccessor - .getMessageType(message.getHeaders()); - if (!this.matchingMessageTypes.contains(messageType)) { - return super.preSend(message, channel); - } - Map sessionHeaders = SimpMessageHeaderAccessor - .getSessionAttributes(message.getHeaders()); - String sessionId = sessionHeaders == null ? null - : (String) sessionHeaders.get(SPRING_SESSION_ID_ATTR_NAME); - if (sessionId != null) { - S session = this.sessionRepository.getSession(sessionId); - if (session != null) { - // update the last accessed time - session.setLastAccessedTime(System.currentTimeMillis()); - this.sessionRepository.save(session); - } - } - return super.preSend(message, channel); - } - - public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, - WebSocketHandler wsHandler, Map attributes) throws Exception { - if (request instanceof ServletServerHttpRequest) { - ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request; - HttpSession session = servletRequest.getServletRequest().getSession(false); - if (session != null) { - setSessionId(attributes, session.getId()); - } - } - return true; - } - - public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, - WebSocketHandler wsHandler, Exception exception) { - } - - public static String getSessionId(Map attributes) { - return (String) attributes.get(SPRING_SESSION_ID_ATTR_NAME); - } - - public static void setSessionId(Map attributes, String sessionId) { - attributes.put(SPRING_SESSION_ID_ATTR_NAME, sessionId); - } -} diff --git a/spring-session/src/main/resources/org/springframework/session/jdbc/schema-db2.sql b/spring-session/src/main/resources/org/springframework/session/jdbc/schema-db2.sql deleted file mode 100644 index a2c1ad2..0000000 --- a/spring-session/src/main/resources/org/springframework/session/jdbc/schema-db2.sql +++ /dev/null @@ -1,20 +0,0 @@ -CREATE TABLE SPRING_SESSION ( - SESSION_ID CHAR(36) NOT NULL, - CREATION_TIME BIGINT NOT NULL, - LAST_ACCESS_TIME BIGINT NOT NULL, - MAX_INACTIVE_INTERVAL INT NOT NULL, - PRINCIPAL_NAME VARCHAR(100), - CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (SESSION_ID) -); - -CREATE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (LAST_ACCESS_TIME); - -CREATE TABLE SPRING_SESSION_ATTRIBUTES ( - SESSION_ID CHAR(36) NOT NULL, - ATTRIBUTE_NAME VARCHAR(200) NOT NULL, - ATTRIBUTE_BYTES BLOB NOT NULL, - CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_ID, ATTRIBUTE_NAME), - CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_ID) REFERENCES SPRING_SESSION(SESSION_ID) ON DELETE CASCADE -); - -CREATE INDEX SPRING_SESSION_ATTRIBUTES_IX1 ON SPRING_SESSION_ATTRIBUTES (SESSION_ID); diff --git a/spring-session/src/main/resources/org/springframework/session/jdbc/schema-derby.sql b/spring-session/src/main/resources/org/springframework/session/jdbc/schema-derby.sql deleted file mode 100644 index a2c1ad2..0000000 --- a/spring-session/src/main/resources/org/springframework/session/jdbc/schema-derby.sql +++ /dev/null @@ -1,20 +0,0 @@ -CREATE TABLE SPRING_SESSION ( - SESSION_ID CHAR(36) NOT NULL, - CREATION_TIME BIGINT NOT NULL, - LAST_ACCESS_TIME BIGINT NOT NULL, - MAX_INACTIVE_INTERVAL INT NOT NULL, - PRINCIPAL_NAME VARCHAR(100), - CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (SESSION_ID) -); - -CREATE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (LAST_ACCESS_TIME); - -CREATE TABLE SPRING_SESSION_ATTRIBUTES ( - SESSION_ID CHAR(36) NOT NULL, - ATTRIBUTE_NAME VARCHAR(200) NOT NULL, - ATTRIBUTE_BYTES BLOB NOT NULL, - CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_ID, ATTRIBUTE_NAME), - CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_ID) REFERENCES SPRING_SESSION(SESSION_ID) ON DELETE CASCADE -); - -CREATE INDEX SPRING_SESSION_ATTRIBUTES_IX1 ON SPRING_SESSION_ATTRIBUTES (SESSION_ID); diff --git a/spring-session/src/main/resources/org/springframework/session/jdbc/schema-drop-db2.sql b/spring-session/src/main/resources/org/springframework/session/jdbc/schema-drop-db2.sql deleted file mode 100644 index 1ff3c6f..0000000 --- a/spring-session/src/main/resources/org/springframework/session/jdbc/schema-drop-db2.sql +++ /dev/null @@ -1,2 +0,0 @@ -DROP TABLE SPRING_SESSION_ATTRIBUTES; -DROP TABLE SPRING_SESSION; diff --git a/spring-session/src/main/resources/org/springframework/session/jdbc/schema-drop-derby.sql b/spring-session/src/main/resources/org/springframework/session/jdbc/schema-drop-derby.sql deleted file mode 100644 index 1ff3c6f..0000000 --- a/spring-session/src/main/resources/org/springframework/session/jdbc/schema-drop-derby.sql +++ /dev/null @@ -1,2 +0,0 @@ -DROP TABLE SPRING_SESSION_ATTRIBUTES; -DROP TABLE SPRING_SESSION; diff --git a/spring-session/src/main/resources/org/springframework/session/jdbc/schema-drop-h2.sql b/spring-session/src/main/resources/org/springframework/session/jdbc/schema-drop-h2.sql deleted file mode 100644 index 5339ff6..0000000 --- a/spring-session/src/main/resources/org/springframework/session/jdbc/schema-drop-h2.sql +++ /dev/null @@ -1,2 +0,0 @@ -DROP TABLE IF EXISTS SPRING_SESSION_ATTRIBUTES; -DROP TABLE IF EXISTS SPRING_SESSION; diff --git a/spring-session/src/main/resources/org/springframework/session/jdbc/schema-drop-hsqldb.sql b/spring-session/src/main/resources/org/springframework/session/jdbc/schema-drop-hsqldb.sql deleted file mode 100644 index a727589..0000000 --- a/spring-session/src/main/resources/org/springframework/session/jdbc/schema-drop-hsqldb.sql +++ /dev/null @@ -1,2 +0,0 @@ -DROP TABLE SPRING_SESSION_ATTRIBUTES IF EXISTS; -DROP TABLE SPRING_SESSION IF EXISTS; diff --git a/spring-session/src/main/resources/org/springframework/session/jdbc/schema-drop-mysql.sql b/spring-session/src/main/resources/org/springframework/session/jdbc/schema-drop-mysql.sql deleted file mode 100644 index 5339ff6..0000000 --- a/spring-session/src/main/resources/org/springframework/session/jdbc/schema-drop-mysql.sql +++ /dev/null @@ -1,2 +0,0 @@ -DROP TABLE IF EXISTS SPRING_SESSION_ATTRIBUTES; -DROP TABLE IF EXISTS SPRING_SESSION; diff --git a/spring-session/src/main/resources/org/springframework/session/jdbc/schema-drop-oracle.sql b/spring-session/src/main/resources/org/springframework/session/jdbc/schema-drop-oracle.sql deleted file mode 100644 index 1ff3c6f..0000000 --- a/spring-session/src/main/resources/org/springframework/session/jdbc/schema-drop-oracle.sql +++ /dev/null @@ -1,2 +0,0 @@ -DROP TABLE SPRING_SESSION_ATTRIBUTES; -DROP TABLE SPRING_SESSION; diff --git a/spring-session/src/main/resources/org/springframework/session/jdbc/schema-drop-postgresql.sql b/spring-session/src/main/resources/org/springframework/session/jdbc/schema-drop-postgresql.sql deleted file mode 100644 index 5339ff6..0000000 --- a/spring-session/src/main/resources/org/springframework/session/jdbc/schema-drop-postgresql.sql +++ /dev/null @@ -1,2 +0,0 @@ -DROP TABLE IF EXISTS SPRING_SESSION_ATTRIBUTES; -DROP TABLE IF EXISTS SPRING_SESSION; diff --git a/spring-session/src/main/resources/org/springframework/session/jdbc/schema-drop-sqlite.sql b/spring-session/src/main/resources/org/springframework/session/jdbc/schema-drop-sqlite.sql deleted file mode 100644 index 5339ff6..0000000 --- a/spring-session/src/main/resources/org/springframework/session/jdbc/schema-drop-sqlite.sql +++ /dev/null @@ -1,2 +0,0 @@ -DROP TABLE IF EXISTS SPRING_SESSION_ATTRIBUTES; -DROP TABLE IF EXISTS SPRING_SESSION; diff --git a/spring-session/src/main/resources/org/springframework/session/jdbc/schema-drop-sqlserver.sql b/spring-session/src/main/resources/org/springframework/session/jdbc/schema-drop-sqlserver.sql deleted file mode 100644 index 1ff3c6f..0000000 --- a/spring-session/src/main/resources/org/springframework/session/jdbc/schema-drop-sqlserver.sql +++ /dev/null @@ -1,2 +0,0 @@ -DROP TABLE SPRING_SESSION_ATTRIBUTES; -DROP TABLE SPRING_SESSION; diff --git a/spring-session/src/main/resources/org/springframework/session/jdbc/schema-drop-sybase.sql b/spring-session/src/main/resources/org/springframework/session/jdbc/schema-drop-sybase.sql deleted file mode 100644 index 1ff3c6f..0000000 --- a/spring-session/src/main/resources/org/springframework/session/jdbc/schema-drop-sybase.sql +++ /dev/null @@ -1,2 +0,0 @@ -DROP TABLE SPRING_SESSION_ATTRIBUTES; -DROP TABLE SPRING_SESSION; diff --git a/spring-session/src/main/resources/org/springframework/session/jdbc/schema-h2.sql b/spring-session/src/main/resources/org/springframework/session/jdbc/schema-h2.sql deleted file mode 100644 index d3278d3..0000000 --- a/spring-session/src/main/resources/org/springframework/session/jdbc/schema-h2.sql +++ /dev/null @@ -1,20 +0,0 @@ -CREATE TABLE SPRING_SESSION ( - SESSION_ID CHAR(36) NOT NULL, - CREATION_TIME BIGINT NOT NULL, - LAST_ACCESS_TIME BIGINT NOT NULL, - MAX_INACTIVE_INTERVAL INT NOT NULL, - PRINCIPAL_NAME VARCHAR(100), - CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (SESSION_ID) -); - -CREATE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (LAST_ACCESS_TIME); - -CREATE TABLE SPRING_SESSION_ATTRIBUTES ( - SESSION_ID CHAR(36) NOT NULL, - ATTRIBUTE_NAME VARCHAR(200) NOT NULL, - ATTRIBUTE_BYTES LONGVARBINARY NOT NULL, - CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_ID, ATTRIBUTE_NAME), - CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_ID) REFERENCES SPRING_SESSION(SESSION_ID) ON DELETE CASCADE -); - -CREATE INDEX SPRING_SESSION_ATTRIBUTES_IX1 ON SPRING_SESSION_ATTRIBUTES (SESSION_ID); diff --git a/spring-session/src/main/resources/org/springframework/session/jdbc/schema-hsqldb.sql b/spring-session/src/main/resources/org/springframework/session/jdbc/schema-hsqldb.sql deleted file mode 100644 index d3278d3..0000000 --- a/spring-session/src/main/resources/org/springframework/session/jdbc/schema-hsqldb.sql +++ /dev/null @@ -1,20 +0,0 @@ -CREATE TABLE SPRING_SESSION ( - SESSION_ID CHAR(36) NOT NULL, - CREATION_TIME BIGINT NOT NULL, - LAST_ACCESS_TIME BIGINT NOT NULL, - MAX_INACTIVE_INTERVAL INT NOT NULL, - PRINCIPAL_NAME VARCHAR(100), - CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (SESSION_ID) -); - -CREATE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (LAST_ACCESS_TIME); - -CREATE TABLE SPRING_SESSION_ATTRIBUTES ( - SESSION_ID CHAR(36) NOT NULL, - ATTRIBUTE_NAME VARCHAR(200) NOT NULL, - ATTRIBUTE_BYTES LONGVARBINARY NOT NULL, - CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_ID, ATTRIBUTE_NAME), - CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_ID) REFERENCES SPRING_SESSION(SESSION_ID) ON DELETE CASCADE -); - -CREATE INDEX SPRING_SESSION_ATTRIBUTES_IX1 ON SPRING_SESSION_ATTRIBUTES (SESSION_ID); diff --git a/spring-session/src/main/resources/org/springframework/session/jdbc/schema-mysql.sql b/spring-session/src/main/resources/org/springframework/session/jdbc/schema-mysql.sql deleted file mode 100644 index 0739d69..0000000 --- a/spring-session/src/main/resources/org/springframework/session/jdbc/schema-mysql.sql +++ /dev/null @@ -1,20 +0,0 @@ -CREATE TABLE SPRING_SESSION ( - SESSION_ID CHAR(36) NOT NULL, - CREATION_TIME BIGINT NOT NULL, - LAST_ACCESS_TIME BIGINT NOT NULL, - MAX_INACTIVE_INTERVAL INT NOT NULL, - PRINCIPAL_NAME VARCHAR(100), - CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (SESSION_ID) -) ENGINE=InnoDB; - -CREATE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (LAST_ACCESS_TIME); - -CREATE TABLE SPRING_SESSION_ATTRIBUTES ( - SESSION_ID CHAR(36) NOT NULL, - ATTRIBUTE_NAME VARCHAR(200) NOT NULL, - ATTRIBUTE_BYTES BLOB NOT NULL, - CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_ID, ATTRIBUTE_NAME), - CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_ID) REFERENCES SPRING_SESSION(SESSION_ID) ON DELETE CASCADE -) ENGINE=InnoDB; - -CREATE INDEX SPRING_SESSION_ATTRIBUTES_IX1 ON SPRING_SESSION_ATTRIBUTES (SESSION_ID); diff --git a/spring-session/src/main/resources/org/springframework/session/jdbc/schema-oracle.sql b/spring-session/src/main/resources/org/springframework/session/jdbc/schema-oracle.sql deleted file mode 100644 index 2444869..0000000 --- a/spring-session/src/main/resources/org/springframework/session/jdbc/schema-oracle.sql +++ /dev/null @@ -1,20 +0,0 @@ -CREATE TABLE SPRING_SESSION ( - SESSION_ID CHAR(36) NOT NULL, - CREATION_TIME NUMBER(19,0) NOT NULL, - LAST_ACCESS_TIME NUMBER(19,0) NOT NULL, - MAX_INACTIVE_INTERVAL NUMBER(10,0) NOT NULL, - PRINCIPAL_NAME VARCHAR2(100 CHAR), - CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (SESSION_ID) -); - -CREATE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (LAST_ACCESS_TIME); - -CREATE TABLE SPRING_SESSION_ATTRIBUTES ( - SESSION_ID CHAR(36) NOT NULL, - ATTRIBUTE_NAME VARCHAR2(200 CHAR) NOT NULL, - ATTRIBUTE_BYTES BLOB NOT NULL, - CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_ID, ATTRIBUTE_NAME), - CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_ID) REFERENCES SPRING_SESSION(SESSION_ID) ON DELETE CASCADE -); - -CREATE INDEX SPRING_SESSION_ATTRIBUTES_IX1 ON SPRING_SESSION_ATTRIBUTES (SESSION_ID); diff --git a/spring-session/src/main/resources/org/springframework/session/jdbc/schema-postgresql.sql b/spring-session/src/main/resources/org/springframework/session/jdbc/schema-postgresql.sql deleted file mode 100644 index 4889ec7..0000000 --- a/spring-session/src/main/resources/org/springframework/session/jdbc/schema-postgresql.sql +++ /dev/null @@ -1,20 +0,0 @@ -CREATE TABLE SPRING_SESSION ( - SESSION_ID CHAR(36) NOT NULL, - CREATION_TIME BIGINT NOT NULL, - LAST_ACCESS_TIME BIGINT NOT NULL, - MAX_INACTIVE_INTERVAL INT NOT NULL, - PRINCIPAL_NAME VARCHAR(100), - CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (SESSION_ID) -); - -CREATE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (LAST_ACCESS_TIME); - -CREATE TABLE SPRING_SESSION_ATTRIBUTES ( - SESSION_ID CHAR(36) NOT NULL, - ATTRIBUTE_NAME VARCHAR(200) NOT NULL, - ATTRIBUTE_BYTES BYTEA NOT NULL, - CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_ID, ATTRIBUTE_NAME), - CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_ID) REFERENCES SPRING_SESSION(SESSION_ID) ON DELETE CASCADE -); - -CREATE INDEX SPRING_SESSION_ATTRIBUTES_IX1 ON SPRING_SESSION_ATTRIBUTES (SESSION_ID); diff --git a/spring-session/src/main/resources/org/springframework/session/jdbc/schema-sqlite.sql b/spring-session/src/main/resources/org/springframework/session/jdbc/schema-sqlite.sql deleted file mode 100644 index c2590c0..0000000 --- a/spring-session/src/main/resources/org/springframework/session/jdbc/schema-sqlite.sql +++ /dev/null @@ -1,20 +0,0 @@ -CREATE TABLE SPRING_SESSION ( - SESSION_ID CHARACTER(36) NOT NULL, - CREATION_TIME INTEGER NOT NULL, - LAST_ACCESS_TIME INTEGER NOT NULL, - MAX_INACTIVE_INTERVAL INTEGER NOT NULL, - PRINCIPAL_NAME VARCHAR(100), - CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (SESSION_ID) -); - -CREATE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (LAST_ACCESS_TIME); - -CREATE TABLE SPRING_SESSION_ATTRIBUTES ( - SESSION_ID CHAR(36) NOT NULL, - ATTRIBUTE_NAME VARCHAR(200) NOT NULL, - ATTRIBUTE_BYTES BLOB NOT NULL, - CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_ID, ATTRIBUTE_NAME), - CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_ID) REFERENCES SPRING_SESSION(SESSION_ID) ON DELETE CASCADE -); - -CREATE INDEX SPRING_SESSION_ATTRIBUTES_IX1 ON SPRING_SESSION_ATTRIBUTES (SESSION_ID); diff --git a/spring-session/src/main/resources/org/springframework/session/jdbc/schema-sqlserver.sql b/spring-session/src/main/resources/org/springframework/session/jdbc/schema-sqlserver.sql deleted file mode 100644 index 1613362..0000000 --- a/spring-session/src/main/resources/org/springframework/session/jdbc/schema-sqlserver.sql +++ /dev/null @@ -1,20 +0,0 @@ -CREATE TABLE SPRING_SESSION ( - SESSION_ID CHAR(36) NOT NULL, - CREATION_TIME BIGINT NOT NULL, - LAST_ACCESS_TIME BIGINT NOT NULL, - MAX_INACTIVE_INTERVAL INT NOT NULL, - PRINCIPAL_NAME VARCHAR(100), - CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (SESSION_ID) -); - -CREATE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (LAST_ACCESS_TIME); - -CREATE TABLE SPRING_SESSION_ATTRIBUTES ( - SESSION_ID CHAR(36) NOT NULL, - ATTRIBUTE_NAME VARCHAR(200) NOT NULL, - ATTRIBUTE_BYTES IMAGE NOT NULL, - CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_ID, ATTRIBUTE_NAME), - CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_ID) REFERENCES SPRING_SESSION(SESSION_ID) ON DELETE CASCADE -); - -CREATE INDEX SPRING_SESSION_ATTRIBUTES_IX1 ON SPRING_SESSION_ATTRIBUTES (SESSION_ID); diff --git a/spring-session/src/main/resources/org/springframework/session/jdbc/schema-sybase.sql b/spring-session/src/main/resources/org/springframework/session/jdbc/schema-sybase.sql deleted file mode 100644 index 1695dde..0000000 --- a/spring-session/src/main/resources/org/springframework/session/jdbc/schema-sybase.sql +++ /dev/null @@ -1,20 +0,0 @@ -CREATE TABLE SPRING_SESSION ( - SESSION_ID CHAR(36) NOT NULL, - CREATION_TIME BIGINT NOT NULL, - LAST_ACCESS_TIME BIGINT NOT NULL, - MAX_INACTIVE_INTERVAL INT NOT NULL, - PRINCIPAL_NAME VARCHAR(100), - CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (SESSION_ID) -) LOCK DATAROWS; - -CREATE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (LAST_ACCESS_TIME); - -CREATE TABLE SPRING_SESSION_ATTRIBUTES ( - SESSION_ID CHAR(36) NOT NULL, - ATTRIBUTE_NAME VARCHAR(200) NOT NULL, - ATTRIBUTE_BYTES IMAGE NOT NULL, - CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_ID, ATTRIBUTE_NAME), - CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_ID) REFERENCES SPRING_SESSION(SESSION_ID) ON DELETE CASCADE -) LOCK DATAROWS; - -CREATE INDEX SPRING_SESSION_ATTRIBUTES_IX1 ON SPRING_SESSION_ATTRIBUTES (SESSION_ID); diff --git a/spring-session/src/test/java/org/springframework/session/MapSessionRepositoryTests.java b/spring-session/src/test/java/org/springframework/session/MapSessionRepositoryTests.java deleted file mode 100644 index 0c3bffd..0000000 --- a/spring-session/src/test/java/org/springframework/session/MapSessionRepositoryTests.java +++ /dev/null @@ -1,67 +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; - -import java.util.concurrent.TimeUnit; - -import org.junit.Before; -import org.junit.Test; - -import static org.assertj.core.api.Assertions.assertThat; - -public class MapSessionRepositoryTests { - MapSessionRepository repository; - - MapSession session; - - @Before - public void setup() { - this.repository = new MapSessionRepository(); - this.session = new MapSession(); - } - - @Test - public void getSessionExpired() { - this.session.setMaxInactiveIntervalInSeconds(1); - this.session.setLastAccessedTime( - System.currentTimeMillis() - TimeUnit.MINUTES.toMillis(5)); - this.repository.save(this.session); - - assertThat(this.repository.getSession(this.session.getId())).isNull(); - } - - @Test - public void createSessionDefaultExpiration() { - ExpiringSession session = this.repository.createSession(); - - assertThat(session).isInstanceOf(MapSession.class); - assertThat(session.getMaxInactiveIntervalInSeconds()) - .isEqualTo(new MapSession().getMaxInactiveIntervalInSeconds()); - } - - @Test - public void createSessionCustomDefaultExpiration() { - final int expectedMaxInterval = new MapSession().getMaxInactiveIntervalInSeconds() - + 10; - this.repository.setDefaultMaxInactiveInterval(expectedMaxInterval); - - ExpiringSession session = this.repository.createSession(); - - assertThat(session.getMaxInactiveIntervalInSeconds()) - .isEqualTo(expectedMaxInterval); - } -} diff --git a/spring-session/src/test/java/org/springframework/session/MapSessionTests.java b/spring-session/src/test/java/org/springframework/session/MapSessionTests.java deleted file mode 100644 index 3088495..0000000 --- a/spring-session/src/test/java/org/springframework/session/MapSessionTests.java +++ /dev/null @@ -1,135 +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; - -import java.util.Set; - -import org.junit.Before; -import org.junit.Test; - -import static org.assertj.core.api.Assertions.assertThat; - -public class MapSessionTests { - - private MapSession session; - - @Before - public void setup() { - this.session = new MapSession(); - this.session.setLastAccessedTime(1413258262962L); - } - - @Test(expected = IllegalArgumentException.class) - public void constructorNullSession() { - new MapSession((ExpiringSession) null); - } - - /** - * Ensure conforms to the javadoc of {@link Session} - */ - @Test - public void setAttributeNullObjectRemoves() { - String attr = "attr"; - this.session.setAttribute(attr, new Object()); - this.session.setAttribute(attr, null); - assertThat(this.session.getAttributeNames()).isEmpty(); - } - - @Test - public void equalsNonSessionFalse() { - assertThat(this.session.equals(new Object())).isFalse(); - } - - @Test - public void equalsCustomSession() { - CustomSession other = new CustomSession(); - this.session.setId(other.getId()); - assertThat(this.session.equals(other)).isTrue(); - } - - @Test - public void hashCodeEqualsIdHashCode() { - this.session.setId("constantId"); - assertThat(this.session.hashCode()).isEqualTo(this.session.getId().hashCode()); - } - - @Test - public void isExpiredExact() { - long now = 1413260062962L; - assertThat(this.session.isExpired(now)).isTrue(); - } - - @Test - public void isExpiredOneMsTooSoon() { - long now = 1413260062961L; - assertThat(this.session.isExpired(now)).isFalse(); - } - - @Test - public void isExpiredOneMsAfter() { - long now = 1413260062963L; - assertThat(this.session.isExpired(now)).isTrue(); - } - - static class CustomSession implements ExpiringSession { - - public long getCreationTime() { - return 0; - } - - public String getId() { - return "id"; - } - - public void setLastAccessedTime(long lastAccessedTime) { - throw new UnsupportedOperationException(); - } - - public long getLastAccessedTime() { - return 0; - } - - public void setMaxInactiveIntervalInSeconds(int interval) { - - } - - public int getMaxInactiveIntervalInSeconds() { - return 0; - } - - public T getAttribute(String attributeName) { - return null; - } - - public Set getAttributeNames() { - return null; - } - - public void setAttribute(String attributeName, Object attributeValue) { - - } - - public void removeAttribute(String attributeName) { - - } - - public boolean isExpired() { - return false; - } - } - -} diff --git a/spring-session/src/test/java/org/springframework/session/config/annotation/web/http/EnableSpringHttpSessionCustomCookieSerializerTests.java b/spring-session/src/test/java/org/springframework/session/config/annotation/web/http/EnableSpringHttpSessionCustomCookieSerializerTests.java deleted file mode 100644 index d69ae9c..0000000 --- a/spring-session/src/test/java/org/springframework/session/config/annotation/web/http/EnableSpringHttpSessionCustomCookieSerializerTests.java +++ /dev/null @@ -1,122 +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.io.IOException; -import java.util.Arrays; - -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; - -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.ExpiringSession; -import org.springframework.session.MapSessionRepository; -import org.springframework.session.web.http.CookieSerializer; -import org.springframework.session.web.http.CookieSerializer.CookieValue; -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.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; - -/** - * @author Rob Winch - * - */ -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration -@WebAppConfiguration -public class EnableSpringHttpSessionCustomCookieSerializerTests { - @Autowired - MockHttpServletRequest request; - @Autowired - MockHttpServletResponse response; - - MockFilterChain chain; - - @Autowired - SessionRepositoryFilter sessionRepositoryFilter; - - @Autowired - CookieSerializer cookieSerializer; - - @Before - public void setup() { - this.chain = new MockFilterChain(); - } - - @Test - public void usesReadSessionIds() throws Exception { - String sessionId = "sessionId"; - given(this.cookieSerializer.readCookieValues(any(HttpServletRequest.class))) - .willReturn(Arrays.asList(sessionId)); - - this.sessionRepositoryFilter.doFilter(this.request, this.response, this.chain); - - assertThat(getRequest().getRequestedSessionId()).isEqualTo(sessionId); - } - - @Test - public void usesWrite() throws Exception { - this.sessionRepositoryFilter.doFilter(this.request, this.response, - new MockFilterChain() { - - @Override - public void doFilter(ServletRequest request, ServletResponse response) - throws IOException, ServletException { - ((HttpServletRequest) request).getSession(); - super.doFilter(request, response); - } - }); - - verify(this.cookieSerializer).writeCookieValue(any(CookieValue.class)); - } - - private HttpServletRequest getRequest() { - return (HttpServletRequest) this.chain.getRequest(); - } - - @EnableSpringHttpSession - @Configuration - static class Config { - @Bean - public MapSessionRepository mapSessionRepository() { - return new MapSessionRepository(); - } - - @Bean - public CookieSerializer cookieSerializer() { - return mock(CookieSerializer.class); - } - } -} diff --git a/spring-session/src/test/java/org/springframework/session/config/annotation/web/http/EnableSpringHttpSessionCustomMultiHttpSessionStrategyTests.java b/spring-session/src/test/java/org/springframework/session/config/annotation/web/http/EnableSpringHttpSessionCustomMultiHttpSessionStrategyTests.java deleted file mode 100644 index 3220274..0000000 --- a/spring-session/src/test/java/org/springframework/session/config/annotation/web/http/EnableSpringHttpSessionCustomMultiHttpSessionStrategyTests.java +++ /dev/null @@ -1,99 +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 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.ExpiringSession; -import org.springframework.session.MapSessionRepository; -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; - -/** - * @author Rob Winch - * - */ -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration -@WebAppConfiguration -public class EnableSpringHttpSessionCustomMultiHttpSessionStrategyTests { - @Autowired - MockHttpServletRequest request; - @Autowired - MockHttpServletResponse response; - - MockFilterChain chain; - - @Autowired - SessionRepositoryFilter sessionRepositoryFilter; - - @Autowired - 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(); - } - - @Bean - public MultiHttpSessionStrategy strategy() { - return mock(MultiHttpSessionStrategy.class); - } - } -} diff --git a/spring-session/src/test/java/org/springframework/session/config/annotation/web/http/SpringHttpSessionConfigurationTests.java b/spring-session/src/test/java/org/springframework/session/config/annotation/web/http/SpringHttpSessionConfigurationTests.java deleted file mode 100644 index 1ed9434..0000000 --- a/spring-session/src/test/java/org/springframework/session/config/annotation/web/http/SpringHttpSessionConfigurationTests.java +++ /dev/null @@ -1,135 +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 org.junit.After; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.junit.runner.RunWith; -import org.mockito.junit.MockitoJUnitRunner; - -import org.springframework.beans.factory.UnsatisfiedDependencyException; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.session.MapSessionRepository; -import org.springframework.session.SessionRepository; -import org.springframework.session.security.web.authentication.SpringSessionRememberMeServices; -import org.springframework.session.web.http.CookieHttpSessionStrategy; -import org.springframework.session.web.http.DefaultCookieSerializer; -import org.springframework.session.web.http.SessionEventHttpSessionListenerAdapter; -import org.springframework.session.web.http.SessionRepositoryFilter; -import org.springframework.test.util.ReflectionTestUtils; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Tests for {@link SpringHttpSessionConfiguration}. - * - * @author Vedran Pavic - */ -@RunWith(MockitoJUnitRunner.class) -public class SpringHttpSessionConfigurationTests { - - @Rule - public final ExpectedException thrown = ExpectedException.none(); - - private AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); - - @After - public void closeContext() { - if (this.context != null) { - this.context.close(); - } - } - - private void registerAndRefresh(Class... annotatedClasses) { - this.context.register(annotatedClasses); - this.context.refresh(); - } - - @Test - public void noSessionRepositoryConfiguration() { - this.thrown.expect(UnsatisfiedDependencyException.class); - this.thrown.expectMessage("org.springframework.session.SessionRepository"); - - registerAndRefresh(EmptyConfiguration.class); - } - - @Test - public void defaultConfiguration() { - registerAndRefresh(DefaultConfiguration.class); - - assertThat(this.context.getBean(SessionEventHttpSessionListenerAdapter.class)) - .isNotNull(); - assertThat(this.context.getBean(SessionRepositoryFilter.class)).isNotNull(); - assertThat(this.context.getBean(SessionRepository.class)).isNotNull(); - } - - @Test - public void rememberMeServicesConfiguration() { - registerAndRefresh(RememberMeServicesConfiguration.class); - - SessionRepositoryFilter sessionRepositoryFilter = this.context.getBean( - SessionRepositoryFilter.class); - assertThat(sessionRepositoryFilter).isNotNull(); - CookieHttpSessionStrategy httpSessionStrategy = - (CookieHttpSessionStrategy) ReflectionTestUtils.getField( - sessionRepositoryFilter, "httpSessionStrategy"); - assertThat(httpSessionStrategy).isNotNull(); - DefaultCookieSerializer cookieSerializer = - (DefaultCookieSerializer) ReflectionTestUtils.getField( - httpSessionStrategy, "cookieSerializer"); - assertThat(cookieSerializer).isNotNull(); - assertThat(ReflectionTestUtils.getField( - cookieSerializer, "rememberMeRequestAttribute")) - .isEqualTo(SpringSessionRememberMeServices.REMEMBER_ME_LOGIN_ATTR); - } - - @Configuration - @EnableSpringHttpSession - static class EmptyConfiguration { - } - - static class BaseConfiguration { - - @Bean - public MapSessionRepository sessionRepository() { - return new MapSessionRepository(); - } - - } - - @Configuration - @EnableSpringHttpSession - static class DefaultConfiguration extends BaseConfiguration { - } - - - @Configuration - @EnableSpringHttpSession - static class RememberMeServicesConfiguration extends BaseConfiguration { - - @Bean - public SpringSessionRememberMeServices rememberMeServices() { - return new SpringSessionRememberMeServices(); - } - - } - -} diff --git a/spring-session/src/test/java/org/springframework/session/data/redis/RedisOperationsSessionRepositoryTests.java b/spring-session/src/test/java/org/springframework/session/data/redis/RedisOperationsSessionRepositoryTests.java deleted file mode 100644 index bf31923..0000000 --- a/spring-session/src/test/java/org/springframework/session/data/redis/RedisOperationsSessionRepositoryTests.java +++ /dev/null @@ -1,722 +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.data.redis; - -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.TimeUnit; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; - -import org.springframework.context.ApplicationEventPublisher; -import org.springframework.data.redis.connection.DefaultMessage; -import org.springframework.data.redis.connection.RedisConnection; -import org.springframework.data.redis.connection.RedisConnectionFactory; -import org.springframework.data.redis.core.BoundHashOperations; -import org.springframework.data.redis.core.BoundSetOperations; -import org.springframework.data.redis.core.BoundValueOperations; -import org.springframework.data.redis.core.RedisOperations; -import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer; -import org.springframework.data.redis.serializer.RedisSerializer; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.authority.AuthorityUtils; -import org.springframework.security.core.context.SecurityContext; -import org.springframework.security.core.context.SecurityContextImpl; -import org.springframework.session.ExpiringSession; -import org.springframework.session.FindByIndexNameSessionRepository; -import org.springframework.session.MapSession; -import org.springframework.session.data.redis.RedisOperationsSessionRepository.PrincipalNameResolver; -import org.springframework.session.data.redis.RedisOperationsSessionRepository.RedisSession; -import org.springframework.session.events.AbstractSessionEvent; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.atLeastOnce; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.reset; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; - -@RunWith(MockitoJUnitRunner.class) -@SuppressWarnings({ "unchecked", "rawtypes" }) -public class RedisOperationsSessionRepositoryTests { - static final String SPRING_SECURITY_CONTEXT_KEY = "SPRING_SECURITY_CONTEXT"; - - @Mock - RedisConnectionFactory factory; - @Mock - RedisConnection connection; - @Mock - RedisOperations redisOperations; - @Mock - BoundValueOperations boundValueOperations; - @Mock - BoundHashOperations boundHashOperations; - @Mock - BoundSetOperations boundSetOperations; - @Mock - ApplicationEventPublisher publisher; - @Mock - RedisSerializer defaultSerializer; - @Captor - ArgumentCaptor event; - @Captor - ArgumentCaptor> delta; - - private MapSession cached; - - private RedisOperationsSessionRepository redisRepository; - - @Before - public void setup() { - this.redisRepository = new RedisOperationsSessionRepository(this.redisOperations); - this.redisRepository.setDefaultSerializer(this.defaultSerializer); - - this.cached = new MapSession(); - this.cached.setId("session-id"); - this.cached.setCreationTime(1404360000000L); - this.cached.setLastAccessedTime(1404360000000L); - } - - @Test(expected = IllegalArgumentException.class) - public void constructorNullConnectionFactory() { - new RedisOperationsSessionRepository((RedisConnectionFactory) null); - } - - @Test(expected = IllegalArgumentException.class) - public void setApplicationEventPublisherNull() { - this.redisRepository.setApplicationEventPublisher(null); - } - - // gh-61 - @Test - public void constructorConnectionFactory() { - this.redisRepository = new RedisOperationsSessionRepository(this.factory); - RedisSession session = this.redisRepository.createSession(); - - given(this.factory.getConnection()).willReturn(this.connection); - - this.redisRepository.save(session); - } - - @Test - public void createSessionDefaultMaxInactiveInterval() throws Exception { - ExpiringSession session = this.redisRepository.createSession(); - assertThat(session.getMaxInactiveIntervalInSeconds()) - .isEqualTo(new MapSession().getMaxInactiveIntervalInSeconds()); - } - - @Test - public void createSessionCustomMaxInactiveInterval() throws Exception { - int interval = 1; - this.redisRepository.setDefaultMaxInactiveInterval(interval); - ExpiringSession session = this.redisRepository.createSession(); - assertThat(session.getMaxInactiveIntervalInSeconds()).isEqualTo(interval); - } - - @Test - public void saveNewSession() { - RedisSession session = this.redisRepository.createSession(); - given(this.redisOperations.boundHashOps(anyString())) - .willReturn(this.boundHashOperations); - given(this.redisOperations.boundSetOps(anyString())) - .willReturn(this.boundSetOperations); - given(this.redisOperations.boundValueOps(anyString())) - .willReturn(this.boundValueOperations); - - this.redisRepository.save(session); - - Map delta = getDelta(); - assertThat(delta.size()).isEqualTo(3); - Object creationTime = delta - .get(RedisOperationsSessionRepository.CREATION_TIME_ATTR); - assertThat(creationTime).isEqualTo(session.getCreationTime()); - assertThat(delta.get(RedisOperationsSessionRepository.MAX_INACTIVE_ATTR)) - .isEqualTo(MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS); - assertThat(delta.get(RedisOperationsSessionRepository.LAST_ACCESSED_ATTR)) - .isEqualTo(session.getCreationTime()); - } - - // gh-467 - @Test - public void saveSessionNothingChanged() { - RedisSession session = this.redisRepository.new RedisSession(this.cached); - - this.redisRepository.save(session); - - verifyZeroInteractions(this.redisOperations); - } - - @Test - public void saveJavadocSummary() { - RedisSession session = this.redisRepository.createSession(); - - String sessionKey = "spring:session:sessions:" + session.getId(); - String backgroundExpireKey = "spring:session:expirations:" - + RedisSessionExpirationPolicy.roundUpToNextMinute( - RedisSessionExpirationPolicy.expiresInMillis(session)); - String destroyedTriggerKey = "spring:session:sessions:expires:" + session.getId(); - - given(this.redisOperations.boundHashOps(sessionKey)) - .willReturn(this.boundHashOperations); - given(this.redisOperations.boundSetOps(backgroundExpireKey)) - .willReturn(this.boundSetOperations); - given(this.redisOperations.boundValueOps(destroyedTriggerKey)) - .willReturn(this.boundValueOperations); - - this.redisRepository.save(session); - - // the actual data in the session expires 5 minutes after expiration so the data - // can be accessed in expiration events - // if the session is retrieved and expired it will not be returned since - // getSession checks if it is expired - long fiveMinutesAfterExpires = session.getMaxInactiveIntervalInSeconds() - + TimeUnit.MINUTES.toSeconds(5); - verify(this.boundHashOperations).expire(fiveMinutesAfterExpires, - TimeUnit.SECONDS); - verify(this.boundSetOperations).expire(fiveMinutesAfterExpires, TimeUnit.SECONDS); - verify(this.boundSetOperations).add("expires:" + session.getId()); - verify(this.boundValueOperations).expire(1800L, TimeUnit.SECONDS); - verify(this.boundValueOperations).append(""); - } - - @Test - public void saveJavadoc() { - RedisSession session = this.redisRepository.new RedisSession(this.cached); - session.setLastAccessedTime(session.getLastAccessedTime()); - - given(this.redisOperations.boundHashOps("spring:session:sessions:session-id")) - .willReturn(this.boundHashOperations); - given(this.redisOperations - .boundSetOps("spring:session:expirations:1404361860000")) - .willReturn(this.boundSetOperations); - given(this.redisOperations - .boundValueOps("spring:session:sessions:expires:session-id")) - .willReturn(this.boundValueOperations); - - this.redisRepository.save(session); - - // the actual data in the session expires 5 minutes after expiration so the data - // can be accessed in expiration events - // if the session is retrieved and expired it will not be returned since - // getSession checks if it is expired - verify(this.boundHashOperations).expire( - session.getMaxInactiveIntervalInSeconds() + TimeUnit.MINUTES.toSeconds(5), - TimeUnit.SECONDS); - } - - @Test - public void saveLastAccessChanged() { - RedisSession session = this.redisRepository.new RedisSession( - new MapSession(this.cached)); - session.setLastAccessedTime(12345678L); - given(this.redisOperations.boundHashOps(anyString())) - .willReturn(this.boundHashOperations); - given(this.redisOperations.boundSetOps(anyString())) - .willReturn(this.boundSetOperations); - given(this.redisOperations.boundValueOps(anyString())) - .willReturn(this.boundValueOperations); - - this.redisRepository.save(session); - - assertThat(getDelta()) - .isEqualTo(map(RedisOperationsSessionRepository.LAST_ACCESSED_ATTR, - session.getLastAccessedTime())); - } - - @Test - public void saveSetAttribute() { - String attrName = "attrName"; - RedisSession session = this.redisRepository.new RedisSession(new MapSession()); - session.setAttribute(attrName, "attrValue"); - given(this.redisOperations.boundHashOps(anyString())) - .willReturn(this.boundHashOperations); - given(this.redisOperations.boundSetOps(anyString())) - .willReturn(this.boundSetOperations); - given(this.redisOperations.boundValueOps(anyString())) - .willReturn(this.boundValueOperations); - - this.redisRepository.save(session); - - assertThat(getDelta()).isEqualTo( - map(RedisOperationsSessionRepository.getSessionAttrNameKey(attrName), - session.getAttribute(attrName))); - } - - @Test - public void saveRemoveAttribute() { - String attrName = "attrName"; - RedisSession session = this.redisRepository.new RedisSession(new MapSession()); - session.removeAttribute(attrName); - given(this.redisOperations.boundHashOps(anyString())) - .willReturn(this.boundHashOperations); - given(this.redisOperations.boundSetOps(anyString())) - .willReturn(this.boundSetOperations); - given(this.redisOperations.boundValueOps(anyString())) - .willReturn(this.boundValueOperations); - - this.redisRepository.save(session); - - assertThat(getDelta()).isEqualTo(map( - RedisOperationsSessionRepository.getSessionAttrNameKey(attrName), null)); - } - - @Test - public void saveExpired() { - RedisSession session = this.redisRepository.new RedisSession(new MapSession()); - session.setMaxInactiveIntervalInSeconds(0); - given(this.redisOperations.boundHashOps(anyString())) - .willReturn(this.boundHashOperations); - given(this.redisOperations.boundSetOps(anyString())) - .willReturn(this.boundSetOperations); - - this.redisRepository.save(session); - - String id = session.getId(); - verify(this.redisOperations, atLeastOnce()).delete(getKey("expires:" + id)); - verify(this.redisOperations, never()).boundValueOps(getKey("expires:" + id)); - } - - @Test - public void redisSessionGetAttributes() { - String attrName = "attrName"; - RedisSession session = this.redisRepository.new RedisSession(); - assertThat(session.getAttributeNames()).isEmpty(); - session.setAttribute(attrName, "attrValue"); - assertThat(session.getAttributeNames()).containsOnly(attrName); - session.removeAttribute(attrName); - assertThat(session.getAttributeNames()).isEmpty(); - } - - @Test - public void delete() { - String attrName = "attrName"; - MapSession expected = new MapSession(); - expected.setLastAccessedTime(System.currentTimeMillis() - 60000); - expected.setAttribute(attrName, "attrValue"); - given(this.redisOperations.boundHashOps(anyString())) - .willReturn(this.boundHashOperations); - given(this.redisOperations.boundSetOps(anyString())) - .willReturn(this.boundSetOperations); - Map map = map(RedisOperationsSessionRepository.getSessionAttrNameKey(attrName), - expected.getAttribute(attrName), - RedisOperationsSessionRepository.CREATION_TIME_ATTR, - expected.getCreationTime(), - RedisOperationsSessionRepository.MAX_INACTIVE_ATTR, - expected.getMaxInactiveIntervalInSeconds(), - RedisOperationsSessionRepository.LAST_ACCESSED_ATTR, - expected.getLastAccessedTime()); - given(this.boundHashOperations.entries()).willReturn(map); - given(this.redisOperations.boundSetOps(anyString())) - .willReturn(this.boundSetOperations); - - String id = expected.getId(); - this.redisRepository.delete(id); - - assertThat(getDelta().get(RedisOperationsSessionRepository.MAX_INACTIVE_ATTR)) - .isEqualTo(0); - verify(this.redisOperations, atLeastOnce()).delete(getKey("expires:" + id)); - verify(this.redisOperations, never()).boundValueOps(getKey("expires:" + id)); - } - - @Test - public void deleteNullSession() { - given(this.redisOperations.boundHashOps(anyString())) - .willReturn(this.boundHashOperations); - - String id = "abc"; - this.redisRepository.delete(id); - verify(this.redisOperations, times(0)).delete(anyString()); - verify(this.redisOperations, times(0)).delete(anyString()); - } - - @Test - public void getSessionNotFound() { - String id = "abc"; - given(this.redisOperations.boundHashOps(getKey(id))) - .willReturn(this.boundHashOperations); - given(this.boundHashOperations.entries()).willReturn(map()); - - assertThat(this.redisRepository.getSession(id)).isNull(); - } - - @Test - public void getSessionFound() { - String attrName = "attrName"; - MapSession expected = new MapSession(); - expected.setLastAccessedTime(System.currentTimeMillis() - 60000); - expected.setAttribute(attrName, "attrValue"); - given(this.redisOperations.boundHashOps(getKey(expected.getId()))) - .willReturn(this.boundHashOperations); - Map map = map(RedisOperationsSessionRepository.getSessionAttrNameKey(attrName), - expected.getAttribute(attrName), - RedisOperationsSessionRepository.CREATION_TIME_ATTR, - expected.getCreationTime(), - RedisOperationsSessionRepository.MAX_INACTIVE_ATTR, - expected.getMaxInactiveIntervalInSeconds(), - RedisOperationsSessionRepository.LAST_ACCESSED_ATTR, - expected.getLastAccessedTime()); - given(this.boundHashOperations.entries()).willReturn(map); - - RedisSession session = this.redisRepository.getSession(expected.getId()); - assertThat(session.getId()).isEqualTo(expected.getId()); - assertThat(session.getAttributeNames()).isEqualTo(expected.getAttributeNames()); - assertThat(session.getAttribute(attrName)) - .isEqualTo(expected.getAttribute(attrName)); - assertThat(session.getCreationTime()).isEqualTo(expected.getCreationTime()); - assertThat(session.getMaxInactiveIntervalInSeconds()) - .isEqualTo(expected.getMaxInactiveIntervalInSeconds()); - assertThat(session.getLastAccessedTime()) - .isEqualTo(expected.getLastAccessedTime()); - - } - - @Test - public void getSessionExpired() { - String expiredId = "expired-id"; - given(this.redisOperations.boundHashOps(getKey(expiredId))) - .willReturn(this.boundHashOperations); - Map map = map(RedisOperationsSessionRepository.MAX_INACTIVE_ATTR, 1, - RedisOperationsSessionRepository.LAST_ACCESSED_ATTR, - System.currentTimeMillis() - TimeUnit.MINUTES.toMillis(5)); - given(this.boundHashOperations.entries()).willReturn(map); - - assertThat(this.redisRepository.getSession(expiredId)).isNull(); - } - - @Test - public void findByPrincipalNameExpired() { - String expiredId = "expired-id"; - given(this.redisOperations.boundSetOps(anyString())) - .willReturn(this.boundSetOperations); - given(this.boundSetOperations.members()) - .willReturn(Collections.singleton(expiredId)); - given(this.redisOperations.boundHashOps(getKey(expiredId))) - .willReturn(this.boundHashOperations); - Map map = map(RedisOperationsSessionRepository.MAX_INACTIVE_ATTR, 1, - RedisOperationsSessionRepository.LAST_ACCESSED_ATTR, - System.currentTimeMillis() - TimeUnit.MINUTES.toMillis(5)); - given(this.boundHashOperations.entries()).willReturn(map); - - assertThat(this.redisRepository.findByIndexNameAndIndexValue( - FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, "principal")) - .isEmpty(); - } - - @Test - public void findByPrincipalName() { - long lastAccessed = System.currentTimeMillis() - 10; - long createdTime = lastAccessed - 10; - int maxInactive = 3600; - String sessionId = "some-id"; - given(this.redisOperations.boundSetOps(anyString())) - .willReturn(this.boundSetOperations); - given(this.boundSetOperations.members()) - .willReturn(Collections.singleton(sessionId)); - given(this.redisOperations.boundHashOps(getKey(sessionId))) - .willReturn(this.boundHashOperations); - Map map = map(RedisOperationsSessionRepository.CREATION_TIME_ATTR, createdTime, - RedisOperationsSessionRepository.MAX_INACTIVE_ATTR, maxInactive, - RedisOperationsSessionRepository.LAST_ACCESSED_ATTR, lastAccessed); - given(this.boundHashOperations.entries()).willReturn(map); - - Map sessionIdToSessions = this.redisRepository - .findByIndexNameAndIndexValue( - FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, - "principal"); - - assertThat(sessionIdToSessions).hasSize(1); - RedisSession session = sessionIdToSessions.get(sessionId); - assertThat(session).isNotNull(); - assertThat(session.getId()).isEqualTo(sessionId); - assertThat(session.getLastAccessedTime()).isEqualTo(lastAccessed); - assertThat(session.getMaxInactiveIntervalInSeconds()).isEqualTo(maxInactive); - assertThat(session.getCreationTime()).isEqualTo(createdTime); - } - - @Test - public void cleanupExpiredSessions() { - String expiredId = "expired-id"; - given(this.redisOperations.boundSetOps(anyString())) - .willReturn(this.boundSetOperations); - - Set expiredIds = new HashSet( - Arrays.asList("expired-key1", "expired-key2")); - given(this.boundSetOperations.members()).willReturn(expiredIds); - - this.redisRepository.cleanupExpiredSessions(); - - for (Object id : expiredIds) { - String expiredKey = "spring:session:sessions:" + id; - // https://github.com/spring-projects/spring-session/issues/93 - verify(this.redisOperations).hasKey(expiredKey); - } - } - - @Test - public void onMessageCreated() throws Exception { - MapSession session = this.cached; - byte[] pattern = "".getBytes("UTF-8"); - String channel = "spring:session:event:created:" + session.getId(); - JdkSerializationRedisSerializer defaultSerailizer = new JdkSerializationRedisSerializer(); - this.redisRepository.setDefaultSerializer(defaultSerailizer); - byte[] body = defaultSerailizer.serialize(new HashMap()); - DefaultMessage message = new DefaultMessage(channel.getBytes("UTF-8"), body); - - this.redisRepository.setApplicationEventPublisher(this.publisher); - - this.redisRepository.onMessage(message, pattern); - - verify(this.publisher).publishEvent(this.event.capture()); - assertThat(this.event.getValue().getSessionId()).isEqualTo(session.getId()); - } - - // gh-309 - @Test - public void onMessageCreatedCustomSerializer() throws Exception { - MapSession session = this.cached; - byte[] pattern = "".getBytes("UTF-8"); - byte[] body = new byte[0]; - String channel = "spring:session:event:created:" + session.getId(); - given(this.defaultSerializer.deserialize(body)) - .willReturn(new HashMap()); - DefaultMessage message = new DefaultMessage(channel.getBytes("UTF-8"), body); - this.redisRepository.setApplicationEventPublisher(this.publisher); - - this.redisRepository.onMessage(message, pattern); - - verify(this.publisher).publishEvent(this.event.capture()); - assertThat(this.event.getValue().getSessionId()).isEqualTo(session.getId()); - verify(this.defaultSerializer).deserialize(body); - } - - @Test - public void resolvePrincipalIndex() { - PrincipalNameResolver resolver = RedisOperationsSessionRepository.PRINCIPAL_NAME_RESOLVER; - String username = "username"; - RedisSession session = this.redisRepository.createSession(); - session.setAttribute(FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, - username); - - assertThat(resolver.resolvePrincipal(session)).isEqualTo(username); - } - - @Test - public void resolveIndexOnSecurityContext() { - String principal = "resolveIndexOnSecurityContext"; - Authentication authentication = new UsernamePasswordAuthenticationToken(principal, - "notused", AuthorityUtils.createAuthorityList("ROLE_USER")); - SecurityContext context = new SecurityContextImpl(); - context.setAuthentication(authentication); - - PrincipalNameResolver resolver = RedisOperationsSessionRepository.PRINCIPAL_NAME_RESOLVER; - - RedisSession session = this.redisRepository.createSession(); - session.setAttribute(SPRING_SECURITY_CONTEXT_KEY, context); - - assertThat(resolver.resolvePrincipal(session)).isEqualTo(principal); - } - - @Test - public void flushModeOnSaveCreate() { - this.redisRepository.createSession(); - - verifyZeroInteractions(this.boundHashOperations); - } - - @Test - public void flushModeOnSaveSetAttribute() { - RedisSession session = this.redisRepository.createSession(); - session.setAttribute("something", "here"); - - verifyZeroInteractions(this.boundHashOperations); - } - - @Test - public void flushModeOnSaveRemoveAttribute() { - RedisSession session = this.redisRepository.createSession(); - session.removeAttribute("remove"); - - verifyZeroInteractions(this.boundHashOperations); - } - - @Test - public void flushModeOnSaveSetLastAccessedTime() { - RedisSession session = this.redisRepository.createSession(); - session.setLastAccessedTime(1L); - - verifyZeroInteractions(this.boundHashOperations); - } - - @Test - public void flushModeOnSaveSetMaxInactiveIntervalInSeconds() { - RedisSession session = this.redisRepository.createSession(); - session.setMaxInactiveIntervalInSeconds(1); - - verifyZeroInteractions(this.boundHashOperations); - } - - @Test - public void flushModeImmediateCreate() { - given(this.redisOperations.boundHashOps(anyString())) - .willReturn(this.boundHashOperations); - given(this.redisOperations.boundSetOps(anyString())) - .willReturn(this.boundSetOperations); - given(this.redisOperations.boundValueOps(anyString())) - .willReturn(this.boundValueOperations); - - this.redisRepository.setRedisFlushMode(RedisFlushMode.IMMEDIATE); - RedisSession session = this.redisRepository.createSession(); - - Map delta = getDelta(); - assertThat(delta.size()).isEqualTo(3); - Object creationTime = delta - .get(RedisOperationsSessionRepository.CREATION_TIME_ATTR); - assertThat(creationTime).isEqualTo(session.getCreationTime()); - assertThat(delta.get(RedisOperationsSessionRepository.MAX_INACTIVE_ATTR)) - .isEqualTo(MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS); - assertThat(delta.get(RedisOperationsSessionRepository.LAST_ACCESSED_ATTR)) - .isEqualTo(session.getCreationTime()); - } - - @Test - public void flushModeImmediateSetAttribute() { - given(this.redisOperations.boundHashOps(anyString())) - .willReturn(this.boundHashOperations); - given(this.redisOperations.boundSetOps(anyString())) - .willReturn(this.boundSetOperations); - given(this.redisOperations.boundValueOps(anyString())) - .willReturn(this.boundValueOperations); - - this.redisRepository.setRedisFlushMode(RedisFlushMode.IMMEDIATE); - RedisSession session = this.redisRepository.createSession(); - String attrName = "someAttribute"; - session.setAttribute(attrName, "someValue"); - - Map delta = getDelta(2); - assertThat(delta.size()).isEqualTo(1); - assertThat(delta).isEqualTo( - map(RedisOperationsSessionRepository.getSessionAttrNameKey(attrName), - session.getAttribute(attrName))); - } - - @Test - public void flushModeImmediateRemoveAttribute() { - given(this.redisOperations.boundHashOps(anyString())) - .willReturn(this.boundHashOperations); - given(this.redisOperations.boundSetOps(anyString())) - .willReturn(this.boundSetOperations); - given(this.redisOperations.boundValueOps(anyString())) - .willReturn(this.boundValueOperations); - - this.redisRepository.setRedisFlushMode(RedisFlushMode.IMMEDIATE); - RedisSession session = this.redisRepository.createSession(); - String attrName = "someAttribute"; - session.removeAttribute(attrName); - - Map delta = getDelta(2); - assertThat(delta.size()).isEqualTo(1); - assertThat(delta).isEqualTo( - map(RedisOperationsSessionRepository.getSessionAttrNameKey(attrName), - session.getAttribute(attrName))); - } - - @Test - public void flushModeSetMaxInactiveIntervalInSeconds() { - given(this.redisOperations.boundHashOps(anyString())) - .willReturn(this.boundHashOperations); - given(this.redisOperations.boundSetOps(anyString())) - .willReturn(this.boundSetOperations); - given(this.redisOperations.boundValueOps(anyString())) - .willReturn(this.boundValueOperations); - - this.redisRepository.setRedisFlushMode(RedisFlushMode.IMMEDIATE); - RedisSession session = this.redisRepository.createSession(); - - reset(this.boundHashOperations); - - session.setMaxInactiveIntervalInSeconds(1); - - verify(this.boundHashOperations).expire(anyLong(), any(TimeUnit.class)); - } - - @Test - public void flushModeSetLastAccessedTime() { - given(this.redisOperations.boundHashOps(anyString())) - .willReturn(this.boundHashOperations); - given(this.redisOperations.boundSetOps(anyString())) - .willReturn(this.boundSetOperations); - given(this.redisOperations.boundValueOps(anyString())) - .willReturn(this.boundValueOperations); - - this.redisRepository.setRedisFlushMode(RedisFlushMode.IMMEDIATE); - RedisSession session = this.redisRepository.createSession(); - - long now = System.currentTimeMillis(); - session.setLastAccessedTime(now); - - Map delta = getDelta(2); - assertThat(delta.size()).isEqualTo(1); - assertThat(delta) - .isEqualTo(map(RedisOperationsSessionRepository.LAST_ACCESSED_ATTR, - session.getLastAccessedTime())); - } - - @Test(expected = IllegalArgumentException.class) - public void setRedisFlushModeNull() { - this.redisRepository.setRedisFlushMode(null); - } - - private String getKey(String id) { - return "spring:session:sessions:" + id; - } - - private Map map(Object... objects) { - Map result = new HashMap(); - if (objects == null) { - return result; - } - for (int i = 0; i < objects.length; i += 2) { - result.put((String) objects[i], objects[i + 1]); - } - return result; - } - - private Map getDelta() { - return getDelta(1); - } - - private Map getDelta(int times) { - verify(this.boundHashOperations, times(times)).putAll(this.delta.capture()); - return this.delta.getAllValues().get(times - 1); - } -} diff --git a/spring-session/src/test/java/org/springframework/session/data/redis/RedisSessionExpirationPolicyTests.java b/spring-session/src/test/java/org/springframework/session/data/redis/RedisSessionExpirationPolicyTests.java deleted file mode 100644 index 6e4dbfb..0000000 --- a/spring-session/src/test/java/org/springframework/session/data/redis/RedisSessionExpirationPolicyTests.java +++ /dev/null @@ -1,172 +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.data.redis; - -import java.util.concurrent.TimeUnit; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; - -import org.springframework.data.redis.core.BoundHashOperations; -import org.springframework.data.redis.core.BoundSetOperations; -import org.springframework.data.redis.core.BoundValueOperations; -import org.springframework.data.redis.core.RedisOperations; -import org.springframework.session.MapSession; - -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.anyString; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; - -/** - * @author Rob Winch - */ -@RunWith(MockitoJUnitRunner.class) -public class RedisSessionExpirationPolicyTests { - // Wed Apr 15 10:28:32 CDT 2015 - final static Long NOW = 1429111712346L; - - // Wed Apr 15 10:27:32 CDT 2015 - final static Long ONE_MINUTE_AGO = 1429111652346L; - - @Mock - RedisOperations sessionRedisOperations; - @Mock - BoundSetOperations setOperations; - @Mock - BoundHashOperations hashOperations; - @Mock - BoundValueOperations valueOperations; - - RedisSessionExpirationPolicy policy; - - private MapSession session; - - @Before - public void setup() { - RedisOperationsSessionRepository repository = new RedisOperationsSessionRepository( - this.sessionRedisOperations); - this.policy = new RedisSessionExpirationPolicy(this.sessionRedisOperations, - repository); - this.session = new MapSession(); - this.session.setLastAccessedTime(1429116694675L); - this.session.setId("12345"); - - given(this.sessionRedisOperations.boundSetOps(anyString())) - .willReturn(this.setOperations); - given(this.sessionRedisOperations.boundHashOps(anyString())) - .willReturn(this.hashOperations); - given(this.sessionRedisOperations.boundValueOps(anyString())) - .willReturn(this.valueOperations); - } - - // gh-169 - @Test - public void onExpirationUpdatedRemovesOriginalExpirationTimeRoundedUp() - throws Exception { - long originalExpirationTimeInMs = ONE_MINUTE_AGO; - long originalRoundedToNextMinInMs = RedisSessionExpirationPolicy - .roundUpToNextMinute(originalExpirationTimeInMs); - String originalExpireKey = this.policy - .getExpirationKey(originalRoundedToNextMinInMs); - - this.policy.onExpirationUpdated(originalExpirationTimeInMs, this.session); - - // verify the original is removed - verify(this.sessionRedisOperations).boundSetOps(originalExpireKey); - verify(this.setOperations).remove("expires:" + this.session.getId()); - } - - @Test - public void onExpirationUpdatedDoNotSendDeleteWhenExpirationTimeDoesNotChange() - throws Exception { - long originalExpirationTimeInMs = RedisSessionExpirationPolicy - .expiresInMillis(this.session) - 10; - long originalRoundedToNextMinInMs = RedisSessionExpirationPolicy - .roundUpToNextMinute(originalExpirationTimeInMs); - String originalExpireKey = this.policy - .getExpirationKey(originalRoundedToNextMinInMs); - - this.policy.onExpirationUpdated(originalExpirationTimeInMs, this.session); - - // verify the original is not removed - verify(this.sessionRedisOperations).boundSetOps(originalExpireKey); - verify(this.setOperations, never()).remove("expires:" + this.session.getId()); - } - - @Test - public void onExpirationUpdatedAddsExpirationTimeRoundedUp() throws Exception { - long expirationTimeInMs = RedisSessionExpirationPolicy - .expiresInMillis(this.session); - long expirationRoundedUpInMs = RedisSessionExpirationPolicy - .roundUpToNextMinute(expirationTimeInMs); - String expectedExpireKey = this.policy.getExpirationKey(expirationRoundedUpInMs); - - this.policy.onExpirationUpdated(null, this.session); - - verify(this.sessionRedisOperations).boundSetOps(expectedExpireKey); - verify(this.setOperations).add("expires:" + this.session.getId()); - verify(this.setOperations).expire(this.session.getMaxInactiveIntervalInSeconds() - + TimeUnit.MINUTES.toSeconds(5), TimeUnit.SECONDS); - } - - @Test - public void onExpirationUpdatedSetExpireSession() throws Exception { - String sessionKey = this.policy.getSessionKey(this.session.getId()); - - this.policy.onExpirationUpdated(null, this.session); - - verify(this.sessionRedisOperations).boundHashOps(sessionKey); - verify(this.hashOperations).expire(this.session.getMaxInactiveIntervalInSeconds() - + TimeUnit.MINUTES.toSeconds(5), TimeUnit.SECONDS); - } - - @Test - public void onExpirationUpdatedDeleteOnZero() throws Exception { - String sessionKey = this.policy.getSessionKey("expires:" + this.session.getId()); - - long originalExpirationTimeInMs = ONE_MINUTE_AGO; - - this.session.setMaxInactiveIntervalInSeconds(0); - - this.policy.onExpirationUpdated(originalExpirationTimeInMs, this.session); - - // verify the original is removed - verify(this.setOperations).remove("expires:" + this.session.getId()); - verify(this.setOperations).add("expires:" + this.session.getId()); - verify(this.sessionRedisOperations).delete(sessionKey); - verify(this.setOperations).expire(this.session.getMaxInactiveIntervalInSeconds() - + TimeUnit.MINUTES.toSeconds(5), TimeUnit.SECONDS); - } - - @Test - public void onExpirationUpdatedPersistOnNegativeExpiration() throws Exception { - long originalExpirationTimeInMs = ONE_MINUTE_AGO; - - this.session.setMaxInactiveIntervalInSeconds(-1); - - this.policy.onExpirationUpdated(originalExpirationTimeInMs, this.session); - - verify(this.setOperations).remove("expires:" + this.session.getId()); - verify(this.valueOperations).append(""); - verify(this.valueOperations).persist(); - verify(this.hashOperations).persist(); - } -} diff --git a/spring-session/src/test/java/org/springframework/session/data/redis/config/annotation/web/http/EnableRedisKeyspaceNotificationsInitializerTests.java b/spring-session/src/test/java/org/springframework/session/data/redis/config/annotation/web/http/EnableRedisKeyspaceNotificationsInitializerTests.java deleted file mode 100644 index c0b1a3a..0000000 --- a/spring-session/src/test/java/org/springframework/session/data/redis/config/annotation/web/http/EnableRedisKeyspaceNotificationsInitializerTests.java +++ /dev/null @@ -1,173 +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.data.redis.config.annotation.web.http; - -import java.util.Arrays; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; - -import org.springframework.data.redis.connection.RedisConnection; -import org.springframework.data.redis.connection.RedisConnectionFactory; -import org.springframework.session.data.redis.config.ConfigureNotifyKeyspaceEventsAction; - -import static org.assertj.core.api.Assertions.assertThat; -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.verify; - -@RunWith(MockitoJUnitRunner.class) -public class EnableRedisKeyspaceNotificationsInitializerTests { - static final String CONFIG_NOTIFY_KEYSPACE_EVENTS = "notify-keyspace-events"; - - @Mock - RedisConnectionFactory connectionFactory; - @Mock - RedisConnection connection; - @Captor - ArgumentCaptor options; - - RedisHttpSessionConfiguration.EnableRedisKeyspaceNotificationsInitializer initializer; - - @Before - public void setup() { - given(this.connectionFactory.getConnection()).willReturn(this.connection); - - this.initializer = new RedisHttpSessionConfiguration.EnableRedisKeyspaceNotificationsInitializer( - this.connectionFactory, new ConfigureNotifyKeyspaceEventsAction()); - } - - @Test - public void afterPropertiesSetUnset() throws Exception { - setConfigNotification(""); - - this.initializer.afterPropertiesSet(); - - assertOptionsContains("E", "g", "x"); - } - - @Test - public void afterPropertiesSetA() throws Exception { - setConfigNotification("A"); - - this.initializer.afterPropertiesSet(); - - assertOptionsContains("A", "E"); - } - - @Test - public void afterPropertiesSetE() throws Exception { - setConfigNotification("E"); - - this.initializer.afterPropertiesSet(); - - assertOptionsContains("E", "g", "x"); - } - - @Test - public void afterPropertiesSetK() throws Exception { - setConfigNotification("K"); - - this.initializer.afterPropertiesSet(); - - assertOptionsContains("K", "E", "g", "x"); - } - - @Test - public void afterPropertiesSetAE() throws Exception { - setConfigNotification("AE"); - - this.initializer.afterPropertiesSet(); - - verify(this.connection, never()).setConfig(anyString(), anyString()); - } - - @Test - public void afterPropertiesSetAK() throws Exception { - setConfigNotification("AK"); - - this.initializer.afterPropertiesSet(); - - assertOptionsContains("A", "K", "E"); - } - - @Test - public void afterPropertiesSetEK() throws Exception { - setConfigNotification("EK"); - - this.initializer.afterPropertiesSet(); - - assertOptionsContains("E", "K", "g", "x"); - } - - @Test - public void afterPropertiesSetEg() throws Exception { - setConfigNotification("Eg"); - - this.initializer.afterPropertiesSet(); - - assertOptionsContains("E", "g", "x"); - } - - @Test - public void afterPropertiesSetE$() throws Exception { - setConfigNotification("E$"); - - this.initializer.afterPropertiesSet(); - - assertOptionsContains("E", "$", "g", "x"); - } - - @Test - public void afterPropertiesSetKg() throws Exception { - setConfigNotification("Kg"); - - this.initializer.afterPropertiesSet(); - - assertOptionsContains("K", "g", "E", "x"); - } - - @Test - public void afterPropertiesSetAEK() throws Exception { - setConfigNotification("AEK"); - - this.initializer.afterPropertiesSet(); - - verify(this.connection, never()).setConfig(anyString(), anyString()); - } - - private void assertOptionsContains(String... expectedValues) { - verify(this.connection).setConfig(eq(CONFIG_NOTIFY_KEYSPACE_EVENTS), - this.options.capture()); - for (String expectedValue : expectedValues) { - assertThat(this.options.getValue()).contains(expectedValue); - } - assertThat(this.options.getValue().length()).isEqualTo(expectedValues.length); - } - - private void setConfigNotification(String value) { - given(this.connection.getConfig(CONFIG_NOTIFY_KEYSPACE_EVENTS)) - .willReturn(Arrays.asList(CONFIG_NOTIFY_KEYSPACE_EVENTS, value)); - } -} diff --git a/spring-session/src/test/java/org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfigurationClassPathXmlApplicationContextTests.java b/spring-session/src/test/java/org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfigurationClassPathXmlApplicationContextTests.java deleted file mode 100644 index 94b0178..0000000 --- a/spring-session/src/test/java/org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfigurationClassPathXmlApplicationContextTests.java +++ /dev/null @@ -1,50 +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.data.redis.config.annotation.web.http; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.data.redis.connection.RedisConnection; -import org.springframework.data.redis.connection.RedisConnectionFactory; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; - -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; - -/** - * @author Rob Winch - * - */ -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration -public class RedisHttpSessionConfigurationClassPathXmlApplicationContextTests { - - // gh-318 - @Test - public void contextLoads() { - } - - static RedisConnectionFactory connectionFactory() { - RedisConnectionFactory factory = mock(RedisConnectionFactory.class); - RedisConnection connection = mock(RedisConnection.class); - given(factory.getConnection()).willReturn(connection); - - return factory; - } -} diff --git a/spring-session/src/test/java/org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfigurationCustomCronTests.java b/spring-session/src/test/java/org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfigurationCustomCronTests.java deleted file mode 100644 index ff6ca9a..0000000 --- a/spring-session/src/test/java/org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfigurationCustomCronTests.java +++ /dev/null @@ -1,80 +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.data.redis.config.annotation.web.http; - -import org.assertj.core.api.ThrowableAssert.ThrowingCallable; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -import org.springframework.context.annotation.AnnotationConfigApplicationContext; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.PropertySource; -import org.springframework.data.redis.connection.RedisConnection; -import org.springframework.data.redis.connection.RedisConnectionFactory; - -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; - -/** - * @author Rob Winch - * - */ -public class RedisHttpSessionConfigurationCustomCronTests { - - AnnotationConfigApplicationContext context; - - @Before - public void setup() { - this.context = new AnnotationConfigApplicationContext(); - } - - @After - public void closeContext() { - if (this.context != null) { - this.context.close(); - } - } - - @Test - public void overrideCron() { - this.context.register(Config.class); - - assertThatThrownBy(new ThrowingCallable() { - public void call() throws Throwable { - RedisHttpSessionConfigurationCustomCronTests.this.context.refresh(); - } - }).hasStackTraceContaining( - "Encountered invalid @Scheduled method 'cleanupExpiredSessions': Cron expression must consist of 6 fields (found 1 in \"oops\")"); - } - - @EnableRedisHttpSession - @Configuration - @PropertySource("classpath:spring-session-cleanup-cron-expression-oops.properties") - static class Config { - @Bean - public RedisConnectionFactory connectionFactory() { - RedisConnectionFactory factory = mock(RedisConnectionFactory.class); - RedisConnection connection = mock(RedisConnection.class); - given(factory.getConnection()).willReturn(connection); - - return factory; - } - } -} diff --git a/spring-session/src/test/java/org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfigurationMockTests.java b/spring-session/src/test/java/org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfigurationMockTests.java deleted file mode 100644 index b91e06d..0000000 --- a/spring-session/src/test/java/org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfigurationMockTests.java +++ /dev/null @@ -1,90 +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.data.redis.config.annotation.web.http; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; - -import org.springframework.data.redis.connection.RedisConnection; -import org.springframework.data.redis.connection.RedisConnectionFactory; -import org.springframework.session.data.redis.config.ConfigureRedisAction; -import org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration.EnableRedisKeyspaceNotificationsInitializer; - -import static org.assertj.core.api.Assertions.failBecauseExceptionWasNotThrown; -import static org.mockito.BDDMockito.given; -import static org.mockito.BDDMockito.willThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; - -@RunWith(MockitoJUnitRunner.class) -public class RedisHttpSessionConfigurationMockTests { - @Mock - RedisConnectionFactory factory; - @Mock - RedisConnection connection; - - @Before - public void setup() { - given(this.factory.getConnection()).willReturn(this.connection); - } - - @Test - public void enableRedisKeyspaceNotificationsInitializerAfterPropertiesSetWhenNoOpThenNoInteractionWithConnectionFactory() - throws Exception { - EnableRedisKeyspaceNotificationsInitializer init = new EnableRedisKeyspaceNotificationsInitializer( - this.factory, ConfigureRedisAction.NO_OP); - - init.afterPropertiesSet(); - - verifyZeroInteractions(this.factory); - } - - @Test - public void enableRedisKeyspaceNotificationsInitializerAfterPropertiesSetWhenExceptionThenCloseConnection() - throws Exception { - ConfigureRedisAction action = mock(ConfigureRedisAction.class); - willThrow(new RuntimeException()).given(action).configure(this.connection); - - EnableRedisKeyspaceNotificationsInitializer init = new EnableRedisKeyspaceNotificationsInitializer( - this.factory, action); - - try { - init.afterPropertiesSet(); - failBecauseExceptionWasNotThrown(Throwable.class); - } - catch (Throwable success) { - } - - verify(this.connection).close(); - } - - @Test - public void enableRedisKeyspaceNotificationsInitializerAfterPropertiesSetWhenNoExceptionThenCloseConnection() - throws Exception { - ConfigureRedisAction action = mock(ConfigureRedisAction.class); - - EnableRedisKeyspaceNotificationsInitializer init = new EnableRedisKeyspaceNotificationsInitializer( - this.factory, action); - - init.afterPropertiesSet(); - - verify(this.connection).close(); - } -} diff --git a/spring-session/src/test/java/org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfigurationNoOpConfigureRedisActionTests.java b/spring-session/src/test/java/org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfigurationNoOpConfigureRedisActionTests.java deleted file mode 100644 index 5c06002..0000000 --- a/spring-session/src/test/java/org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfigurationNoOpConfigureRedisActionTests.java +++ /dev/null @@ -1,58 +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.data.redis.config.annotation.web.http; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.data.redis.connection.RedisConnectionFactory; -import org.springframework.session.data.redis.config.ConfigureRedisAction; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.springframework.test.context.web.WebAppConfiguration; - -import static org.mockito.Mockito.mock; - -/** - * @author Rob Winch - */ -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration -@WebAppConfiguration -public class RedisHttpSessionConfigurationNoOpConfigureRedisActionTests { - - @Test - public void redisConnectionFactoryNotUsedSinceNoValidation() { - } - - @EnableRedisHttpSession - @Configuration - static class Config { - - @Bean - public static ConfigureRedisAction configureRedisAction() { - return ConfigureRedisAction.NO_OP; - } - - @Bean - public RedisConnectionFactory redisConnectionFactory() { - return mock(RedisConnectionFactory.class); - } - } -} diff --git a/spring-session/src/test/java/org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfigurationOverrideDefaultSerializerTests.java b/spring-session/src/test/java/org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfigurationOverrideDefaultSerializerTests.java deleted file mode 100644 index 08f0fcc..0000000 --- a/spring-session/src/test/java/org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfigurationOverrideDefaultSerializerTests.java +++ /dev/null @@ -1,76 +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.data.redis.config.annotation.web.http; - -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.data.redis.connection.RedisConnection; -import org.springframework.data.redis.connection.RedisConnectionFactory; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.data.redis.serializer.RedisSerializer; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.springframework.test.context.web.WebAppConfiguration; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; - -/** - * @author Rob Winch - * - */ -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration -@WebAppConfiguration -public class RedisHttpSessionConfigurationOverrideDefaultSerializerTests { - - @Autowired - RedisTemplate template; - - @Autowired - RedisSerializer defaultRedisSerializer; - - @Test - public void overrideDefaultRedisTemplate() { - assertThat(this.template.getDefaultSerializer()) - .isSameAs(this.defaultRedisSerializer); - } - - @EnableRedisHttpSession - @Configuration - static class Config { - @Bean - @SuppressWarnings("unchecked") - public RedisSerializer springSessionDefaultRedisSerializer() { - return mock(RedisSerializer.class); - } - - @Bean - public RedisConnectionFactory connectionFactory() { - RedisConnectionFactory factory = mock(RedisConnectionFactory.class); - RedisConnection connection = mock(RedisConnection.class); - given(factory.getConnection()).willReturn(connection); - - return factory; - } - } -} diff --git a/spring-session/src/test/java/org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfigurationOverrideSessionTaskExecutor.java b/spring-session/src/test/java/org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfigurationOverrideSessionTaskExecutor.java deleted file mode 100644 index 3556ed7..0000000 --- a/spring-session/src/test/java/org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfigurationOverrideSessionTaskExecutor.java +++ /dev/null @@ -1,79 +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.data.redis.config.annotation.web.http; - -import java.util.concurrent.Executor; - -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.data.redis.connection.RedisConnection; -import org.springframework.data.redis.connection.RedisConnectionFactory; -import org.springframework.data.redis.listener.RedisMessageListenerContainer; -import org.springframework.scheduling.SchedulingAwareRunnable; -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.times; -import static org.mockito.Mockito.verify; - -/** - * @author Vladimir Tsanev - * - */ -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration -@WebAppConfiguration -public class RedisHttpSessionConfigurationOverrideSessionTaskExecutor { - - @Autowired - RedisMessageListenerContainer redisMessageListenerContainer; - - @Autowired - Executor springSessionRedisTaskExecutor; - - @Test - public void overrideSessionTaskExecutor() { - verify(this.springSessionRedisTaskExecutor, times(1)) - .execute(any(SchedulingAwareRunnable.class)); - } - - @EnableRedisHttpSession - @Configuration - static class Config { - @Bean - public Executor springSessionRedisTaskExecutor() { - return mock(Executor.class); - } - - @Bean - public RedisConnectionFactory connectionFactory() { - RedisConnectionFactory factory = mock(RedisConnectionFactory.class); - RedisConnection connection = mock(RedisConnection.class); - given(factory.getConnection()).willReturn(connection); - - return factory; - } - } -} diff --git a/spring-session/src/test/java/org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfigurationOverrideSessionTaskExecutors.java b/spring-session/src/test/java/org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfigurationOverrideSessionTaskExecutors.java deleted file mode 100644 index 49c9401..0000000 --- a/spring-session/src/test/java/org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfigurationOverrideSessionTaskExecutors.java +++ /dev/null @@ -1,89 +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.data.redis.config.annotation.web.http; - -import java.util.concurrent.Executor; - -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.data.redis.connection.RedisConnection; -import org.springframework.data.redis.connection.RedisConnectionFactory; -import org.springframework.data.redis.listener.RedisMessageListenerContainer; -import org.springframework.scheduling.SchedulingAwareRunnable; -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.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -/** - * @author Vladimir Tsanev - * - */ -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration -@WebAppConfiguration -public class RedisHttpSessionConfigurationOverrideSessionTaskExecutors { - - @Autowired - RedisMessageListenerContainer redisMessageListenerContainer; - - @Autowired - Executor springSessionRedisTaskExecutor; - - @Autowired - Executor springSessionRedisSubscriptionExecutor; - - @Test - public void overrideSessionTaskExecutors() { - verify(this.springSessionRedisSubscriptionExecutor, times(1)) - .execute(any(SchedulingAwareRunnable.class)); - verify(this.springSessionRedisTaskExecutor, never()).execute(any(Runnable.class)); - } - - @EnableRedisHttpSession - @Configuration - static class Config { - @Bean - public Executor springSessionRedisTaskExecutor() { - return mock(Executor.class); - } - - @Bean - public Executor springSessionRedisSubscriptionExecutor() { - return mock(Executor.class); - } - - @Bean - public RedisConnectionFactory connectionFactory() { - RedisConnectionFactory factory = mock(RedisConnectionFactory.class); - RedisConnection connection = mock(RedisConnection.class); - given(factory.getConnection()).willReturn(connection); - - return factory; - } - } -} diff --git a/spring-session/src/test/java/org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfigurationTests.java b/spring-session/src/test/java/org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfigurationTests.java deleted file mode 100644 index ba72159..0000000 --- a/spring-session/src/test/java/org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfigurationTests.java +++ /dev/null @@ -1,109 +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.data.redis.config.annotation.web.http; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -import org.springframework.context.annotation.AnnotationConfigApplicationContext; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; -import org.springframework.data.redis.connection.RedisConnection; -import org.springframework.data.redis.connection.RedisConnectionFactory; -import org.springframework.mock.env.MockEnvironment; -import org.springframework.test.util.ReflectionTestUtils; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; - -/** - * @author Eddú Meléndez - */ -public class RedisHttpSessionConfigurationTests { - - private AnnotationConfigApplicationContext context; - - @Before - public void before() { - this.context = new AnnotationConfigApplicationContext(); - } - - @After - public void after() { - if (this.context != null) { - this.context.close(); - } - } - - @Test - public void resolveValue() { - registerAndRefresh(RedisConfig.class, CustomRedisHttpSessionConfiguration.class); - RedisHttpSessionConfiguration configuration = this.context.getBean(RedisHttpSessionConfiguration.class); - assertThat(ReflectionTestUtils.getField(configuration, "redisNamespace")).isEqualTo("myRedisNamespace"); - } - - @Test - public void resolveValueByPlaceholder() { - this.context.setEnvironment(new MockEnvironment().withProperty("session.redis.namespace", "customRedisNamespace")); - registerAndRefresh(RedisConfig.class, PropertySourceConfiguration.class, CustomRedisHttpSessionConfiguration2.class); - RedisHttpSessionConfiguration configuration = this.context.getBean(RedisHttpSessionConfiguration.class); - assertThat(ReflectionTestUtils.getField(configuration, "redisNamespace")).isEqualTo("customRedisNamespace"); - } - - private void registerAndRefresh(Class... annotatedClasses) { - this.context.register(annotatedClasses); - this.context.refresh(); - } - - @Configuration - static class PropertySourceConfiguration { - - @Bean - public PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() { - return new PropertySourcesPlaceholderConfigurer(); - } - - } - - @Configuration - static class RedisConfig { - - @Bean - public RedisConnectionFactory redisConnectionFactory() { - RedisConnectionFactory connectionFactory = mock(RedisConnectionFactory.class); - given(connectionFactory.getConnection()).willReturn(mock(RedisConnection.class)); - return connectionFactory; - } - - } - - @Configuration - @EnableRedisHttpSession(redisNamespace = "myRedisNamespace") - static class CustomRedisHttpSessionConfiguration { - - } - - @Configuration - @EnableRedisHttpSession(redisNamespace = "${session.redis.namespace}") - static class CustomRedisHttpSessionConfiguration2 { - - } - -} diff --git a/spring-session/src/test/java/org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfigurationXmlCustomExpireTests.java b/spring-session/src/test/java/org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfigurationXmlCustomExpireTests.java deleted file mode 100644 index 9bfc91e..0000000 --- a/spring-session/src/test/java/org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfigurationXmlCustomExpireTests.java +++ /dev/null @@ -1,47 +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.data.redis.config.annotation.web.http; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.data.redis.connection.RedisConnection; -import org.springframework.data.redis.connection.RedisConnectionFactory; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.springframework.test.context.web.WebAppConfiguration; - -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; - -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration -@WebAppConfiguration -public class RedisHttpSessionConfigurationXmlCustomExpireTests { - - @Test - public void contextLoads() { - } - - static RedisConnectionFactory connectionFactory() { - RedisConnectionFactory factory = mock(RedisConnectionFactory.class); - RedisConnection connection = mock(RedisConnection.class); - given(factory.getConnection()).willReturn(connection); - - return factory; - } -} diff --git a/spring-session/src/test/java/org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfigurationXmlTests.java b/spring-session/src/test/java/org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfigurationXmlTests.java deleted file mode 100644 index afbe3bb..0000000 --- a/spring-session/src/test/java/org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfigurationXmlTests.java +++ /dev/null @@ -1,47 +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.data.redis.config.annotation.web.http; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.data.redis.connection.RedisConnection; -import org.springframework.data.redis.connection.RedisConnectionFactory; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.springframework.test.context.web.WebAppConfiguration; - -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; - -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration -@WebAppConfiguration -public class RedisHttpSessionConfigurationXmlTests { - - @Test - public void contextLoads() { - } - - static RedisConnectionFactory connectionFactory() { - RedisConnectionFactory factory = mock(RedisConnectionFactory.class); - RedisConnection connection = mock(RedisConnection.class); - given(factory.getConnection()).willReturn(connection); - - return factory; - } -} diff --git a/spring-session/src/test/java/org/springframework/session/data/redis/config/annotation/web/http/gh109/Gh109Tests.java b/spring-session/src/test/java/org/springframework/session/data/redis/config/annotation/web/http/gh109/Gh109Tests.java deleted file mode 100644 index e579bd3..0000000 --- a/spring-session/src/test/java/org/springframework/session/data/redis/config/annotation/web/http/gh109/Gh109Tests.java +++ /dev/null @@ -1,81 +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.data.redis.config.annotation.web.http.gh109; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.springframework.context.ApplicationEventPublisher; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.data.redis.connection.RedisConnection; -import org.springframework.data.redis.connection.RedisConnectionFactory; -import org.springframework.data.redis.core.RedisOperations; -import org.springframework.session.data.redis.RedisOperationsSessionRepository; -import org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.springframework.test.context.web.WebAppConfiguration; - -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; - -/** - * This test must be in a different package than RedisHttpSessionConfiguration. - * - * @author Rob Winch - * @since 1.0.2 - */ -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration -@WebAppConfiguration -public class Gh109Tests { - - @Test - public void loads() { - - } - - @Configuration - static class Config extends RedisHttpSessionConfiguration { - - int sessionTimeout = 100; - - /** - * override sessionRepository construction to set the custom session-timeout - */ - @Bean - @Override - public RedisOperationsSessionRepository sessionRepository( - RedisOperations sessionRedisTemplate, - ApplicationEventPublisher applicationEventPublisher) { - RedisOperationsSessionRepository sessionRepository = new RedisOperationsSessionRepository( - sessionRedisTemplate); - sessionRepository.setDefaultMaxInactiveInterval(this.sessionTimeout); - return sessionRepository; - } - - @Bean - public RedisConnectionFactory redisConnectionFactory() { - RedisConnectionFactory factory = mock(RedisConnectionFactory.class); - RedisConnection connection = mock(RedisConnection.class); - - given(factory.getConnection()).willReturn(connection); - return factory; - } - } -} diff --git a/spring-session/src/test/java/org/springframework/session/hazelcast/HazelcastSessionRepositoryTests.java b/spring-session/src/test/java/org/springframework/session/hazelcast/HazelcastSessionRepositoryTests.java deleted file mode 100644 index a0ae300..0000000 --- a/spring-session/src/test/java/org/springframework/session/hazelcast/HazelcastSessionRepositoryTests.java +++ /dev/null @@ -1,328 +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.hazelcast; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.concurrent.TimeUnit; - -import com.hazelcast.core.IMap; -import com.hazelcast.query.impl.predicates.EqualPredicate; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; - -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.authority.AuthorityUtils; -import org.springframework.session.FindByIndexNameSessionRepository; -import org.springframework.session.MapSession; -import org.springframework.session.hazelcast.HazelcastSessionRepository.HazelcastSession; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.isA; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; - -/** - * Tests for {@link HazelcastSessionRepository}. - * - * @author Vedran Pavic - * @author Aleksandar Stojsavljevic - */ -@RunWith(MockitoJUnitRunner.class) -public class HazelcastSessionRepositoryTests { - - private static final String SPRING_SECURITY_CONTEXT = "SPRING_SECURITY_CONTEXT"; - - @Rule - public ExpectedException thrown = ExpectedException.none(); - - @Mock - private IMap sessions; - - private HazelcastSessionRepository repository; - - @Before - public void setUp() { - this.repository = new HazelcastSessionRepository(this.sessions); - } - - @Test - public void constructorNullHazelcastInstance() { - this.thrown.expect(IllegalArgumentException.class); - this.thrown.expectMessage("Sessions IMap must not be null"); - - new HazelcastSessionRepository(null); - } - - @Test - public void createSessionDefaultMaxInactiveInterval() throws Exception { - HazelcastSession session = this.repository.createSession(); - - assertThat(session.getMaxInactiveIntervalInSeconds()) - .isEqualTo(new MapSession().getMaxInactiveIntervalInSeconds()); - verifyZeroInteractions(this.sessions); - } - - @Test - public void createSessionCustomMaxInactiveInterval() throws Exception { - int interval = 1; - this.repository.setDefaultMaxInactiveInterval(interval); - - HazelcastSession session = this.repository.createSession(); - - assertThat(session.getMaxInactiveIntervalInSeconds()).isEqualTo(interval); - verifyZeroInteractions(this.sessions); - } - - @Test - public void saveNewFlushModeOnSave() { - HazelcastSession session = this.repository.createSession(); - verifyZeroInteractions(this.sessions); - - this.repository.save(session); - verify(this.sessions, times(1)).put(eq(session.getId()), eq(session.getDelegate()), - isA(Long.class), eq(TimeUnit.SECONDS)); - } - - @Test - public void saveNewFlushModeImmediate() { - this.repository.setHazelcastFlushMode(HazelcastFlushMode.IMMEDIATE); - - HazelcastSession session = this.repository.createSession(); - verify(this.sessions, times(1)).put(eq(session.getId()), eq(session.getDelegate()), - isA(Long.class), eq(TimeUnit.SECONDS)); - } - - @Test - public void saveUpdatedAttributeFlushModeOnSave() { - HazelcastSession session = this.repository.createSession(); - session.setAttribute("testName", "testValue"); - verifyZeroInteractions(this.sessions); - - this.repository.save(session); - verify(this.sessions, times(1)).put(eq(session.getId()), eq(session.getDelegate()), - isA(Long.class), eq(TimeUnit.SECONDS)); - } - - @Test - public void saveUpdatedAttributeFlushModeImmediate() { - this.repository.setHazelcastFlushMode(HazelcastFlushMode.IMMEDIATE); - - HazelcastSession session = this.repository.createSession(); - session.setAttribute("testName", "testValue"); - verify(this.sessions, times(2)).put(eq(session.getId()), eq(session.getDelegate()), - isA(Long.class), eq(TimeUnit.SECONDS)); - - this.repository.save(session); - verifyZeroInteractions(this.sessions); - } - - @Test - public void removeAttributeFlushModeOnSave() { - HazelcastSession session = this.repository.createSession(); - session.removeAttribute("testName"); - verifyZeroInteractions(this.sessions); - - this.repository.save(session); - verify(this.sessions, times(1)).put(eq(session.getId()), eq(session.getDelegate()), - isA(Long.class), eq(TimeUnit.SECONDS)); - } - - @Test - public void removeAttributeFlushModeImmediate() { - this.repository.setHazelcastFlushMode(HazelcastFlushMode.IMMEDIATE); - - HazelcastSession session = this.repository.createSession(); - session.removeAttribute("testName"); - verify(this.sessions, times(2)).put(eq(session.getId()), eq(session.getDelegate()), - isA(Long.class), eq(TimeUnit.SECONDS)); - - this.repository.save(session); - verifyZeroInteractions(this.sessions); - } - - @Test - public void saveUpdatedLastAccessedTimeFlushModeOnSave() { - HazelcastSession session = this.repository.createSession(); - session.setLastAccessedTime(System.currentTimeMillis()); - verifyZeroInteractions(this.sessions); - - this.repository.save(session); - verify(this.sessions, times(1)).put(eq(session.getId()), eq(session.getDelegate()), - isA(Long.class), eq(TimeUnit.SECONDS)); - } - - @Test - public void saveUpdatedLastAccessedTimeFlushModeImmediate() { - this.repository.setHazelcastFlushMode(HazelcastFlushMode.IMMEDIATE); - - HazelcastSession session = this.repository.createSession(); - session.setLastAccessedTime(System.currentTimeMillis()); - verify(this.sessions, times(2)).put(eq(session.getId()), eq(session.getDelegate()), - isA(Long.class), eq(TimeUnit.SECONDS)); - - this.repository.save(session); - verifyZeroInteractions(this.sessions); - } - - @Test - public void saveUpdatedMaxInactiveIntervalInSecondsFlushModeOnSave() { - HazelcastSession session = this.repository.createSession(); - session.setMaxInactiveIntervalInSeconds(1); - verifyZeroInteractions(this.sessions); - - this.repository.save(session); - verify(this.sessions, times(1)).put(eq(session.getId()), eq(session.getDelegate()), - isA(Long.class), eq(TimeUnit.SECONDS)); - } - - @Test - public void saveUpdatedMaxInactiveIntervalInSecondsFlushModeImmediate() { - this.repository.setHazelcastFlushMode(HazelcastFlushMode.IMMEDIATE); - - HazelcastSession session = this.repository.createSession(); - session.setMaxInactiveIntervalInSeconds(1); - verify(this.sessions, times(2)).put(eq(session.getId()), eq(session.getDelegate()), - isA(Long.class), eq(TimeUnit.SECONDS)); - - this.repository.save(session); - verifyZeroInteractions(this.sessions); - } - - @Test - public void saveUnchangedFlushModeOnSave() { - HazelcastSession session = this.repository.createSession(); - this.repository.save(session); - verify(this.sessions, times(1)).put(eq(session.getId()), eq(session.getDelegate()), - isA(Long.class), eq(TimeUnit.SECONDS)); - - this.repository.save(session); - verifyZeroInteractions(this.sessions); - } - - @Test - public void saveUnchangedFlushModeImmediate() { - this.repository.setHazelcastFlushMode(HazelcastFlushMode.IMMEDIATE); - - HazelcastSession session = this.repository.createSession(); - verify(this.sessions, times(1)).put(eq(session.getId()), eq(session.getDelegate()), - isA(Long.class), eq(TimeUnit.SECONDS)); - - this.repository.save(session); - verifyZeroInteractions(this.sessions); - } - - @Test - public void getSessionNotFound() { - String sessionId = "testSessionId"; - - HazelcastSession session = this.repository.getSession(sessionId); - - assertThat(session).isNull(); - verify(this.sessions, times(1)).get(eq(sessionId)); - } - - @Test - public void getSessionExpired() { - MapSession expired = new MapSession(); - expired.setLastAccessedTime(System.currentTimeMillis() - - (MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS * 1000 + 1000)); - given(this.sessions.get(eq(expired.getId()))).willReturn(expired); - - HazelcastSession session = this.repository.getSession(expired.getId()); - - assertThat(session).isNull(); - verify(this.sessions, times(1)).get(eq(expired.getId())); - verify(this.sessions, times(1)).remove(eq(expired.getId())); - } - - @Test - public void getSessionFound() { - MapSession saved = new MapSession(); - saved.setAttribute("savedName", "savedValue"); - given(this.sessions.get(eq(saved.getId()))).willReturn(saved); - - HazelcastSession session = this.repository.getSession(saved.getId()); - - assertThat(session.getId()).isEqualTo(saved.getId()); - assertThat(session.getAttribute("savedName")).isEqualTo("savedValue"); - verify(this.sessions, times(1)).get(eq(saved.getId())); - } - - @Test - public void delete() { - String sessionId = "testSessionId"; - - this.repository.delete(sessionId); - - verify(this.sessions, times(1)).remove(eq(sessionId)); - } - - @Test - public void findByIndexNameAndIndexValueUnknownIndexName() { - String indexValue = "testIndexValue"; - - Map sessions = this.repository.findByIndexNameAndIndexValue( - "testIndexName", indexValue); - - assertThat(sessions).isEmpty(); - verifyZeroInteractions(this.sessions); - } - - @Test - public void findByIndexNameAndIndexValuePrincipalIndexNameNotFound() { - String principal = "username"; - - Map sessions = this.repository.findByIndexNameAndIndexValue( - FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, principal); - - assertThat(sessions).isEmpty(); - verify(this.sessions, times(1)).values(isA(EqualPredicate.class)); - } - - @Test - public void findByIndexNameAndIndexValuePrincipalIndexNameFound() { - String principal = "username"; - Authentication authentication = new UsernamePasswordAuthenticationToken(principal, - "notused", AuthorityUtils.createAuthorityList("ROLE_USER")); - List saved = new ArrayList(2); - MapSession saved1 = new MapSession(); - saved1.setAttribute(SPRING_SECURITY_CONTEXT, authentication); - saved.add(saved1); - MapSession saved2 = new MapSession(); - saved2.setAttribute(SPRING_SECURITY_CONTEXT, authentication); - saved.add(saved2); - given(this.sessions.values(isA(EqualPredicate.class))).willReturn(saved); - - Map sessions = this.repository.findByIndexNameAndIndexValue( - FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, principal); - - assertThat(sessions).hasSize(2); - verify(this.sessions, times(1)).values(isA(EqualPredicate.class)); - } - -} diff --git a/spring-session/src/test/java/org/springframework/session/hazelcast/config/annotation/web/http/HazelcastHttpSessionConfigurationTests.java b/spring-session/src/test/java/org/springframework/session/hazelcast/config/annotation/web/http/HazelcastHttpSessionConfigurationTests.java deleted file mode 100644 index bb04204..0000000 --- a/spring-session/src/test/java/org/springframework/session/hazelcast/config/annotation/web/http/HazelcastHttpSessionConfigurationTests.java +++ /dev/null @@ -1,240 +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.hazelcast.config.annotation.web.http; - -import com.hazelcast.core.HazelcastInstance; -import com.hazelcast.core.IMap; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; - -import org.springframework.beans.factory.UnsatisfiedDependencyException; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.session.hazelcast.HazelcastFlushMode; -import org.springframework.session.hazelcast.HazelcastSessionRepository; -import org.springframework.test.util.ReflectionTestUtils; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.isA; -import static org.mockito.BDDMockito.given; - -/** - * Tests for {@link HazelcastHttpSessionConfiguration}. - * - * @author Vedran Pavic - * @author Aleksandar Stojsavljevic - */ -@RunWith(MockitoJUnitRunner.class) -public class HazelcastHttpSessionConfigurationTests { - - private static final String MAP_NAME = "spring:test:sessions"; - - private static final int MAX_INACTIVE_INTERVAL_IN_SECONDS = 600; - - private static final HazelcastFlushMode HAZELCAST_FLUSH_MODE = HazelcastFlushMode.IMMEDIATE; - - @Rule - public final ExpectedException thrown = ExpectedException.none(); - - @Mock - private static HazelcastInstance hazelcastInstance; - - @Mock - private IMap sessions; - - private AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); - - @Before - public void setUp() { - given(hazelcastInstance.getMap(isA(String.class))).willReturn(this.sessions); - } - - @After - public void closeContext() { - if (this.context != null) { - this.context.close(); - } - } - - @Test - public void noHazelcastInstanceConfiguration() { - this.thrown.expect(UnsatisfiedDependencyException.class); - this.thrown.expectMessage("HazelcastInstance"); - - registerAndRefresh(EmptyConfiguration.class); - } - - @Test - public void defaultConfiguration() { - registerAndRefresh(DefaultConfiguration.class); - - assertThat(this.context.getBean(HazelcastSessionRepository.class)) - .isNotNull(); - } - - @Test - public void customTableName() { - registerAndRefresh(CustomSessionMapNameConfiguration.class); - - HazelcastSessionRepository repository = this.context - .getBean(HazelcastSessionRepository.class); - HazelcastHttpSessionConfiguration configuration = this.context - .getBean(HazelcastHttpSessionConfiguration.class); - assertThat(repository).isNotNull(); - assertThat(ReflectionTestUtils.getField(configuration, "sessionMapName")) - .isEqualTo(MAP_NAME); - } - - @Test - public void setCustomSessionMapName() { - registerAndRefresh(BaseConfiguration.class, - CustomSessionMapNameSetConfiguration.class); - - HazelcastSessionRepository repository = this.context - .getBean(HazelcastSessionRepository.class); - HazelcastHttpSessionConfiguration configuration = this.context - .getBean(HazelcastHttpSessionConfiguration.class); - assertThat(repository).isNotNull(); - assertThat(ReflectionTestUtils.getField(configuration, "sessionMapName")) - .isEqualTo(MAP_NAME); - } - - @Test - public void setCustomMaxInactiveIntervalInSeconds() { - registerAndRefresh(BaseConfiguration.class, - CustomMaxInactiveIntervalInSecondsSetConfiguration.class); - - HazelcastSessionRepository repository = this.context - .getBean(HazelcastSessionRepository.class); - assertThat(repository).isNotNull(); - assertThat(ReflectionTestUtils.getField(repository, "defaultMaxInactiveInterval")).isEqualTo( - MAX_INACTIVE_INTERVAL_IN_SECONDS); - } - - @Test - public void customMaxInactiveIntervalInSeconds() { - registerAndRefresh(CustomMaxInactiveIntervalInSecondsConfiguration.class); - - HazelcastSessionRepository repository = this.context - .getBean(HazelcastSessionRepository.class); - assertThat(repository).isNotNull(); - assertThat(ReflectionTestUtils.getField(repository, "defaultMaxInactiveInterval")) - .isEqualTo(MAX_INACTIVE_INTERVAL_IN_SECONDS); - } - - @Test - public void customFlushImmediately() { - registerAndRefresh(CustomFlushImmediatelyConfiguration.class); - - HazelcastSessionRepository repository = this.context - .getBean(HazelcastSessionRepository.class); - assertThat(repository).isNotNull(); - assertThat(ReflectionTestUtils.getField(repository, "hazelcastFlushMode")) - .isEqualTo(HazelcastFlushMode.IMMEDIATE); - } - - @Test - public void setCustomFlushImmediately() { - registerAndRefresh(BaseConfiguration.class, - CustomFlushImmediatelySetConfiguration.class); - - HazelcastSessionRepository repository = this.context - .getBean(HazelcastSessionRepository.class); - assertThat(repository).isNotNull(); - assertThat(ReflectionTestUtils.getField(repository, "hazelcastFlushMode")) - .isEqualTo(HazelcastFlushMode.IMMEDIATE); - } - - private void registerAndRefresh(Class... annotatedClasses) { - this.context.register(annotatedClasses); - this.context.refresh(); - } - - @Configuration - @EnableHazelcastHttpSession - static class EmptyConfiguration { - } - - static class BaseConfiguration { - - @Bean - public HazelcastInstance hazelcastInstance() { - return hazelcastInstance; - } - - } - - @Configuration - @EnableHazelcastHttpSession - static class DefaultConfiguration extends BaseConfiguration { - } - - @Configuration - @EnableHazelcastHttpSession(sessionMapName = MAP_NAME) - static class CustomSessionMapNameConfiguration extends BaseConfiguration { - } - - @Configuration - static class CustomSessionMapNameSetConfiguration - extends HazelcastHttpSessionConfiguration { - - CustomSessionMapNameSetConfiguration() { - setSessionMapName(MAP_NAME); - } - - } - - @Configuration - static class CustomMaxInactiveIntervalInSecondsSetConfiguration - extends HazelcastHttpSessionConfiguration { - - CustomMaxInactiveIntervalInSecondsSetConfiguration() { - setMaxInactiveIntervalInSeconds(MAX_INACTIVE_INTERVAL_IN_SECONDS); - } - - } - - @Configuration - @EnableHazelcastHttpSession(maxInactiveIntervalInSeconds = MAX_INACTIVE_INTERVAL_IN_SECONDS) - static class CustomMaxInactiveIntervalInSecondsConfiguration - extends BaseConfiguration { - } - - @Configuration - static class CustomFlushImmediatelySetConfiguration - extends HazelcastHttpSessionConfiguration { - - CustomFlushImmediatelySetConfiguration() { - setHazelcastFlushMode(HAZELCAST_FLUSH_MODE); - } - - } - - @Configuration - @EnableHazelcastHttpSession(hazelcastFlushMode = HazelcastFlushMode.IMMEDIATE) - static class CustomFlushImmediatelyConfiguration - extends BaseConfiguration { - } - -} diff --git a/spring-session/src/test/java/org/springframework/session/jdbc/JdbcOperationsSessionRepositoryTests.java b/spring-session/src/test/java/org/springframework/session/jdbc/JdbcOperationsSessionRepositoryTests.java deleted file mode 100644 index 886701f..0000000 --- a/spring-session/src/test/java/org/springframework/session/jdbc/JdbcOperationsSessionRepositoryTests.java +++ /dev/null @@ -1,534 +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.jdbc; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import javax.sql.DataSource; - -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; - -import org.springframework.jdbc.core.BatchPreparedStatementSetter; -import org.springframework.jdbc.core.JdbcOperations; -import org.springframework.jdbc.core.PreparedStatementSetter; -import org.springframework.jdbc.core.ResultSetExtractor; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.authority.AuthorityUtils; -import org.springframework.session.FindByIndexNameSessionRepository; -import org.springframework.session.MapSession; -import org.springframework.test.util.ReflectionTestUtils; -import org.springframework.transaction.PlatformTransactionManager; -import org.springframework.transaction.TransactionDefinition; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.AdditionalMatchers.and; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.contains; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.isA; -import static org.mockito.ArgumentMatchers.startsWith; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.atLeastOnce; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.verifyZeroInteractions; - -/** - * Tests for {@link JdbcOperationsSessionRepository}. - * - * @author Vedran Pavic - * @since 1.2.0 - */ -@RunWith(MockitoJUnitRunner.class) -public class JdbcOperationsSessionRepositoryTests { - - private static final String SPRING_SECURITY_CONTEXT = "SPRING_SECURITY_CONTEXT"; - - @Rule - public ExpectedException thrown = ExpectedException.none(); - - @Mock - private DataSource dataSource; - - @Mock - private JdbcOperations jdbcOperations; - - @Mock - private PlatformTransactionManager transactionManager; - - private JdbcOperationsSessionRepository repository; - - @Before - public void setUp() { - this.repository = new JdbcOperationsSessionRepository( - this.jdbcOperations, this.transactionManager); - } - - @Test - public void constructorDataSource() { - JdbcOperationsSessionRepository repository = new JdbcOperationsSessionRepository( - this.dataSource, this.transactionManager); - - assertThat(ReflectionTestUtils.getField(repository, "jdbcOperations")) - .isNotNull(); - } - - @Test - public void constructorNullDataSource() { - this.thrown.expect(IllegalArgumentException.class); - this.thrown.expectMessage("Property 'dataSource' is required"); - - new JdbcOperationsSessionRepository((DataSource) null, this.transactionManager); - } - - @Test - public void constructorNullJdbcOperations() { - this.thrown.expect(IllegalArgumentException.class); - this.thrown.expectMessage("JdbcOperations must not be null"); - - new JdbcOperationsSessionRepository((JdbcOperations) null, this.transactionManager); - } - - @Test - public void constructorNullTransactionManager() { - this.thrown.expect(IllegalArgumentException.class); - this.thrown.expectMessage("Property 'transactionManager' is required"); - - new JdbcOperationsSessionRepository(this.jdbcOperations, null); - } - - @Test - public void setTableNameNull() { - this.thrown.expect(IllegalArgumentException.class); - this.thrown.expectMessage("Table name must not be empty"); - - this.repository.setTableName(null); - } - - @Test - public void setTableNameEmpty() { - this.thrown.expect(IllegalArgumentException.class); - this.thrown.expectMessage("Table name must not be empty"); - - this.repository.setTableName(" "); - } - - @Test - public void setCreateSessionQueryNull() { - this.thrown.expect(IllegalArgumentException.class); - this.thrown.expectMessage("Query must not be empty"); - - this.repository.setCreateSessionQuery(null); - } - - @Test - public void setCreateSessionQueryEmpty() { - this.thrown.expect(IllegalArgumentException.class); - this.thrown.expectMessage("Query must not be empty"); - - this.repository.setCreateSessionQuery(" "); - } - - @Test - public void setCreateSessionAttributeQueryNull() { - this.thrown.expect(IllegalArgumentException.class); - this.thrown.expectMessage("Query must not be empty"); - - this.repository.setCreateSessionAttributeQuery(null); - } - - @Test - public void setCreateSessionAttributeQueryEmpty() { - this.thrown.expect(IllegalArgumentException.class); - this.thrown.expectMessage("Query must not be empty"); - - this.repository.setCreateSessionAttributeQuery(" "); - } - - @Test - public void setGetSessionQueryNull() { - this.thrown.expect(IllegalArgumentException.class); - this.thrown.expectMessage("Query must not be empty"); - - this.repository.setGetSessionQuery(null); - } - - @Test - public void setGetSessionQueryEmpty() { - this.thrown.expect(IllegalArgumentException.class); - this.thrown.expectMessage("Query must not be empty"); - - this.repository.setGetSessionQuery(" "); - } - - @Test - public void setUpdateSessionQueryNull() { - this.thrown.expect(IllegalArgumentException.class); - this.thrown.expectMessage("Query must not be empty"); - - this.repository.setUpdateSessionQuery(null); - } - - @Test - public void setUpdateSessionQueryEmpty() { - this.thrown.expect(IllegalArgumentException.class); - this.thrown.expectMessage("Query must not be empty"); - - this.repository.setUpdateSessionQuery(" "); - } - - @Test - public void setUpdateSessionAttributeQueryNull() { - this.thrown.expect(IllegalArgumentException.class); - this.thrown.expectMessage("Query must not be empty"); - - this.repository.setUpdateSessionAttributeQuery(null); - } - - @Test - public void setUpdateSessionAttributeQueryEmpty() { - this.thrown.expect(IllegalArgumentException.class); - this.thrown.expectMessage("Query must not be empty"); - - this.repository.setUpdateSessionAttributeQuery(" "); - } - - @Test - public void setDeleteSessionAttributeQueryNull() { - this.thrown.expect(IllegalArgumentException.class); - this.thrown.expectMessage("Query must not be empty"); - - this.repository.setDeleteSessionAttributeQuery(null); - } - - @Test - public void setDeleteSessionAttributeQueryEmpty() { - this.thrown.expect(IllegalArgumentException.class); - this.thrown.expectMessage("Query must not be empty"); - - this.repository.setDeleteSessionAttributeQuery(" "); - } - - @Test - public void setDeleteSessionQueryNull() { - this.thrown.expect(IllegalArgumentException.class); - this.thrown.expectMessage("Query must not be empty"); - - this.repository.setDeleteSessionQuery(null); - } - - @Test - public void setDeleteSessionQueryEmpty() { - this.thrown.expect(IllegalArgumentException.class); - this.thrown.expectMessage("Query must not be empty"); - - this.repository.setDeleteSessionQuery(" "); - } - - @Test - public void setListSessionsByPrincipalNameQueryNull() { - this.thrown.expect(IllegalArgumentException.class); - this.thrown.expectMessage("Query must not be empty"); - - this.repository.setListSessionsByPrincipalNameQuery(null); - } - - @Test - public void setListSessionsByPrincipalNameQueryEmpty() { - this.thrown.expect(IllegalArgumentException.class); - this.thrown.expectMessage("Query must not be empty"); - - this.repository.setListSessionsByPrincipalNameQuery(" "); - } - - @Test - public void setDeleteSessionsByLastAccessTimeQueryNull() { - this.thrown.expect(IllegalArgumentException.class); - this.thrown.expectMessage("Query must not be empty"); - - this.repository.setDeleteSessionsByLastAccessTimeQuery(null); - } - - @Test - public void setDeleteSessionsByLastAccessTimeQueryEmpty() { - this.thrown.expect(IllegalArgumentException.class); - this.thrown.expectMessage("Query must not be empty"); - - this.repository.setDeleteSessionsByLastAccessTimeQuery(" "); - } - - @Test - public void setLobHandlerNull() { - this.thrown.expect(IllegalArgumentException.class); - this.thrown.expectMessage("LobHandler must not be null"); - - this.repository.setLobHandler(null); - } - - @Test - public void setConversionServiceNull() { - this.thrown.expect(IllegalArgumentException.class); - this.thrown.expectMessage("conversionService must not be null"); - - this.repository.setConversionService(null); - } - - @Test - public void createSessionDefaultMaxInactiveInterval() throws Exception { - JdbcOperationsSessionRepository.JdbcSession session = this.repository - .createSession(); - - assertThat(session.isNew()).isTrue(); - assertThat(session.getMaxInactiveIntervalInSeconds()) - .isEqualTo(new MapSession().getMaxInactiveIntervalInSeconds()); - verifyZeroInteractions(this.jdbcOperations); - } - - @Test - public void createSessionCustomMaxInactiveInterval() throws Exception { - int interval = 1; - this.repository.setDefaultMaxInactiveInterval(interval); - - JdbcOperationsSessionRepository.JdbcSession session = this.repository - .createSession(); - - assertThat(session.isNew()).isTrue(); - assertThat(session.getMaxInactiveIntervalInSeconds()).isEqualTo(interval); - verifyZeroInteractions(this.jdbcOperations); - } - - @Test - public void saveNewWithoutAttributes() { - JdbcOperationsSessionRepository.JdbcSession session = this.repository - .createSession(); - - this.repository.save(session); - - assertThat(session.isNew()).isFalse(); - assertPropagationRequiresNew(); - verify(this.jdbcOperations, times(1)).update(startsWith("INSERT"), - isA(PreparedStatementSetter.class)); - verifyNoMoreInteractions(this.jdbcOperations); - } - - @Test - public void saveNewWithAttributes() { - JdbcOperationsSessionRepository.JdbcSession session = this.repository - .createSession(); - session.setAttribute("testName", "testValue"); - - this.repository.save(session); - - assertThat(session.isNew()).isFalse(); - assertPropagationRequiresNew(); - verify(this.jdbcOperations, times(1)).update(startsWith("INSERT"), - isA(PreparedStatementSetter.class)); - verify(this.jdbcOperations, times(1)).batchUpdate( - and(startsWith("INSERT"), contains("ATTRIBUTE_BYTES")), - isA(BatchPreparedStatementSetter.class)); - } - - @Test - public void saveUpdatedAttributes() { - JdbcOperationsSessionRepository.JdbcSession session = this.repository.new JdbcSession( - new MapSession()); - session.setAttribute("testName", "testValue"); - - this.repository.save(session); - - assertThat(session.isNew()).isFalse(); - assertPropagationRequiresNew(); - verify(this.jdbcOperations, times(1)).update( - and(startsWith("UPDATE"), contains("ATTRIBUTE_BYTES")), - isA(PreparedStatementSetter.class)); - } - - @Test - public void saveUpdatedLastAccessedTime() { - JdbcOperationsSessionRepository.JdbcSession session = this.repository.new JdbcSession( - new MapSession()); - session.setLastAccessedTime(System.currentTimeMillis()); - - this.repository.save(session); - - assertThat(session.isNew()).isFalse(); - assertPropagationRequiresNew(); - verify(this.jdbcOperations, times(1)).update( - and(startsWith("UPDATE"), contains("LAST_ACCESS_TIME")), - isA(PreparedStatementSetter.class)); - } - - @Test - public void saveUnchanged() { - JdbcOperationsSessionRepository.JdbcSession session = this.repository.new JdbcSession( - new MapSession()); - - this.repository.save(session); - - assertThat(session.isNew()).isFalse(); - verifyZeroInteractions(this.jdbcOperations); - } - - @Test - public void getSessionNotFound() { - String sessionId = "testSessionId"; - given(this.jdbcOperations.query(isA(String.class), - isA(PreparedStatementSetter.class), isA(ResultSetExtractor.class))) - .willReturn(Collections.emptyList()); - - JdbcOperationsSessionRepository.JdbcSession session = this.repository - .getSession(sessionId); - - assertThat(session).isNull(); - assertPropagationRequiresNew(); - verify(this.jdbcOperations, times(1)).query(isA(String.class), - isA(PreparedStatementSetter.class), isA(ResultSetExtractor.class)); - } - - @Test - public void getSessionExpired() { - MapSession expired = new MapSession(); - expired.setLastAccessedTime(System.currentTimeMillis() - - (MapSession.DEFAULT_MAX_INACTIVE_INTERVAL_SECONDS * 1000 + 1000)); - given(this.jdbcOperations.query(isA(String.class), - isA(PreparedStatementSetter.class), isA(ResultSetExtractor.class))) - .willReturn(Collections.singletonList(expired)); - - JdbcOperationsSessionRepository.JdbcSession session = this.repository - .getSession(expired.getId()); - - assertThat(session).isNull(); - assertPropagationRequiresNew(); - verify(this.jdbcOperations, times(1)).query(isA(String.class), - isA(PreparedStatementSetter.class), isA(ResultSetExtractor.class)); - verify(this.jdbcOperations, times(1)).update(startsWith("DELETE"), - eq(expired.getId())); - } - - @Test - public void getSessionFound() { - MapSession saved = new MapSession(); - saved.setAttribute("savedName", "savedValue"); - given(this.jdbcOperations.query(isA(String.class), - isA(PreparedStatementSetter.class), isA(ResultSetExtractor.class))) - .willReturn(Collections.singletonList(saved)); - - JdbcOperationsSessionRepository.JdbcSession session = this.repository - .getSession(saved.getId()); - - assertThat(session.getId()).isEqualTo(saved.getId()); - assertThat(session.isNew()).isFalse(); - assertThat(session.getAttribute("savedName")).isEqualTo("savedValue"); - assertPropagationRequiresNew(); - verify(this.jdbcOperations, times(1)).query(isA(String.class), - isA(PreparedStatementSetter.class), isA(ResultSetExtractor.class)); - } - - @Test - public void delete() { - String sessionId = "testSessionId"; - - this.repository.delete(sessionId); - - assertPropagationRequiresNew(); - verify(this.jdbcOperations, times(1)).update(startsWith("DELETE"), eq(sessionId)); - } - - @Test - public void findByIndexNameAndIndexValueUnknownIndexName() { - String indexValue = "testIndexValue"; - - Map sessions = this.repository - .findByIndexNameAndIndexValue("testIndexName", indexValue); - - assertThat(sessions).isEmpty(); - verifyZeroInteractions(this.jdbcOperations); - } - - @Test - public void findByIndexNameAndIndexValuePrincipalIndexNameNotFound() { - String principal = "username"; - given(this.jdbcOperations.query(isA(String.class), - isA(PreparedStatementSetter.class), isA(ResultSetExtractor.class))) - .willReturn(Collections.emptyList()); - - Map sessions = this.repository - .findByIndexNameAndIndexValue( - FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, - principal); - - assertThat(sessions).isEmpty(); - assertPropagationRequiresNew(); - verify(this.jdbcOperations, times(1)).query(isA(String.class), - isA(PreparedStatementSetter.class), isA(ResultSetExtractor.class)); - } - - @Test - public void findByIndexNameAndIndexValuePrincipalIndexNameFound() { - String principal = "username"; - Authentication authentication = new UsernamePasswordAuthenticationToken(principal, - "notused", AuthorityUtils.createAuthorityList("ROLE_USER")); - List saved = new ArrayList(2); - MapSession saved1 = new MapSession(); - saved1.setAttribute(SPRING_SECURITY_CONTEXT, authentication); - saved.add(saved1); - MapSession saved2 = new MapSession(); - saved2.setAttribute(SPRING_SECURITY_CONTEXT, authentication); - saved.add(saved2); - given(this.jdbcOperations.query(isA(String.class), - isA(PreparedStatementSetter.class), isA(ResultSetExtractor.class))) - .willReturn(saved); - - Map sessions = this.repository - .findByIndexNameAndIndexValue( - FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, - principal); - - assertThat(sessions).hasSize(2); - assertPropagationRequiresNew(); - verify(this.jdbcOperations, times(1)).query(isA(String.class), - isA(PreparedStatementSetter.class), isA(ResultSetExtractor.class)); - } - - @Test - public void cleanupExpiredSessions() { - this.repository.cleanUpExpiredSessions(); - - assertPropagationRequiresNew(); - verify(this.jdbcOperations, times(1)).update(startsWith("DELETE"), anyLong()); - } - - private void assertPropagationRequiresNew() { - ArgumentCaptor argument = - ArgumentCaptor.forClass(TransactionDefinition.class); - verify(this.transactionManager, atLeastOnce()).getTransaction(argument.capture()); - assertThat(argument.getValue().getPropagationBehavior()) - .isEqualTo(TransactionDefinition.PROPAGATION_REQUIRES_NEW); - } - -} diff --git a/spring-session/src/test/java/org/springframework/session/jdbc/config/annotation/web/http/JdbcHttpSessionConfigurationCustomCronTests.java b/spring-session/src/test/java/org/springframework/session/jdbc/config/annotation/web/http/JdbcHttpSessionConfigurationCustomCronTests.java deleted file mode 100644 index 67ea095..0000000 --- a/spring-session/src/test/java/org/springframework/session/jdbc/config/annotation/web/http/JdbcHttpSessionConfigurationCustomCronTests.java +++ /dev/null @@ -1,81 +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.jdbc.config.annotation.web.http; - -import javax.sql.DataSource; - -import org.assertj.core.api.ThrowableAssert.ThrowingCallable; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -import org.springframework.context.annotation.AnnotationConfigApplicationContext; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.PropertySource; -import org.springframework.transaction.PlatformTransactionManager; - -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.mockito.Mockito.mock; - -/** - * @author Rob Winch - * - */ -public class JdbcHttpSessionConfigurationCustomCronTests { - - AnnotationConfigApplicationContext context; - - @Before - public void setup() { - this.context = new AnnotationConfigApplicationContext(); - } - - @After - public void closeContext() { - if (this.context != null) { - this.context.close(); - } - } - - @Test - public void overrideCron() { - this.context.register(Config.class); - - assertThatThrownBy(new ThrowingCallable() { - public void call() throws Throwable { - JdbcHttpSessionConfigurationCustomCronTests.this.context.refresh(); - } - }).hasStackTraceContaining( - "Encountered invalid @Scheduled method 'cleanUpExpiredSessions': Cron expression must consist of 6 fields (found 1 in \"oops\")"); - } - - @EnableJdbcHttpSession - @Configuration - @PropertySource("classpath:spring-session-cleanup-cron-expression-oops.properties") - static class Config { - @Bean - public DataSource dataSource() { - return mock(DataSource.class); - } - - @Bean - public PlatformTransactionManager transactionManager() { - return mock(PlatformTransactionManager.class); - } - } -} diff --git a/spring-session/src/test/java/org/springframework/session/jdbc/config/annotation/web/http/JdbcHttpSessionConfigurationTests.java b/spring-session/src/test/java/org/springframework/session/jdbc/config/annotation/web/http/JdbcHttpSessionConfigurationTests.java deleted file mode 100644 index 99105c1..0000000 --- a/spring-session/src/test/java/org/springframework/session/jdbc/config/annotation/web/http/JdbcHttpSessionConfigurationTests.java +++ /dev/null @@ -1,275 +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.jdbc.config.annotation.web.http; - -import javax.sql.DataSource; - -import org.junit.After; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -import org.springframework.beans.factory.UnsatisfiedDependencyException; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; -import org.springframework.core.convert.ConversionService; -import org.springframework.jdbc.support.lob.LobHandler; -import org.springframework.mock.env.MockEnvironment; -import org.springframework.session.jdbc.JdbcOperationsSessionRepository; -import org.springframework.test.util.ReflectionTestUtils; -import org.springframework.transaction.PlatformTransactionManager; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; - -/** - * Tests for {@link JdbcHttpSessionConfiguration}. - * - * @author Vedran Pavic - * @author Eddú Meléndez - * @since 1.2.0 - */ -public class JdbcHttpSessionConfigurationTests { - - private static final String TABLE_NAME = "TEST_SESSION"; - - private static final int MAX_INACTIVE_INTERVAL_IN_SECONDS = 600; - - private static final String TABLE_NAME_SYSTEM_PROPERTY = "spring.session.jdbc.tableName"; - - @Rule - public final ExpectedException thrown = ExpectedException.none(); - - private AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); - - @After - public void closeContext() { - if (this.context != null) { - this.context.close(); - } - } - - @Test - public void noDataSourceConfiguration() { - this.thrown.expect(UnsatisfiedDependencyException.class); - this.thrown.expectMessage("springSessionJdbcOperations"); - - registerAndRefresh(EmptyConfiguration.class); - } - - @Test - public void defaultConfiguration() { - registerAndRefresh(DefaultConfiguration.class); - - assertThat(this.context.getBean(JdbcOperationsSessionRepository.class)) - .isNotNull(); - } - - @Test - public void customTableName() { - registerAndRefresh(CustomTableNameConfiguration.class); - - JdbcOperationsSessionRepository repository = this.context - .getBean(JdbcOperationsSessionRepository.class); - assertThat(repository).isNotNull(); - assertThat(ReflectionTestUtils.getField(repository, "tableName")) - .isEqualTo(TABLE_NAME); - } - - @Test - public void customTableNameSystemProperty() { - System.setProperty(TABLE_NAME_SYSTEM_PROPERTY, TABLE_NAME); - - try { - registerAndRefresh(DefaultConfiguration.class); - - JdbcOperationsSessionRepository repository = this.context - .getBean(JdbcOperationsSessionRepository.class); - assertThat(repository).isNotNull(); - assertThat(ReflectionTestUtils.getField(repository, "tableName")) - .isEqualTo(TABLE_NAME); - } - finally { - System.clearProperty(TABLE_NAME_SYSTEM_PROPERTY); - } - } - - @Test - public void setCustomTableName() { - registerAndRefresh(BaseConfiguration.class, - CustomTableNameSetConfiguration.class); - - JdbcHttpSessionConfiguration repository = this.context - .getBean(JdbcHttpSessionConfiguration.class); - assertThat(repository).isNotNull(); - assertThat(ReflectionTestUtils.getField(repository, "tableName")).isEqualTo( - "custom_session"); - } - - @Test - public void setCustomMaxInactiveIntervalInSeconds() { - registerAndRefresh(BaseConfiguration.class, - CustomMaxInactiveIntervalInSecondsSetConfiguration.class); - - JdbcHttpSessionConfiguration repository = this.context - .getBean(JdbcHttpSessionConfiguration.class); - assertThat(repository).isNotNull(); - assertThat(ReflectionTestUtils.getField(repository, "maxInactiveIntervalInSeconds")).isEqualTo( - 10); - } - - @Test - public void customMaxInactiveIntervalInSeconds() { - registerAndRefresh(CustomMaxInactiveIntervalInSecondsConfiguration.class); - - JdbcOperationsSessionRepository repository = this.context - .getBean(JdbcOperationsSessionRepository.class); - assertThat(repository).isNotNull(); - assertThat(ReflectionTestUtils.getField(repository, "defaultMaxInactiveInterval")) - .isEqualTo(MAX_INACTIVE_INTERVAL_IN_SECONDS); - } - - @Test - public void customLobHandlerConfiguration() { - registerAndRefresh(CustomLobHandlerConfiguration.class); - - JdbcOperationsSessionRepository repository = this.context - .getBean(JdbcOperationsSessionRepository.class); - LobHandler lobHandler = this.context.getBean(LobHandler.class); - assertThat(repository).isNotNull(); - assertThat(lobHandler).isNotNull(); - assertThat(ReflectionTestUtils.getField(repository, "lobHandler")) - .isEqualTo(lobHandler); - } - - @Test - public void customConversionServiceConfiguration() { - registerAndRefresh(CustomConversionServiceConfiguration.class); - - JdbcOperationsSessionRepository repository = this.context - .getBean(JdbcOperationsSessionRepository.class); - ConversionService conversionService = this.context - .getBean("springSessionConversionService", ConversionService.class); - assertThat(repository).isNotNull(); - assertThat(conversionService).isNotNull(); - Object repositoryConversionService = ReflectionTestUtils.getField(repository, - "conversionService"); - assertThat(repositoryConversionService).isEqualTo(conversionService); - } - - @Test - public void resolveTableNameByPropertyPlaceholder() { - this.context.setEnvironment(new MockEnvironment().withProperty("session.jdbc.tableName", "custom_session_table")); - registerAndRefresh(CustomJdbcHttpSessionConfiguration.class); - JdbcHttpSessionConfiguration configuration = this.context.getBean(JdbcHttpSessionConfiguration.class); - assertThat(ReflectionTestUtils.getField(configuration, "tableName")).isEqualTo("custom_session_table"); - } - - private void registerAndRefresh(Class... annotatedClasses) { - this.context.register(annotatedClasses); - this.context.refresh(); - } - - @Configuration - @EnableJdbcHttpSession - static class EmptyConfiguration { - } - - static class BaseConfiguration { - - @Bean - public DataSource dataSource() { - return mock(DataSource.class); - } - - @Bean - public PlatformTransactionManager transactionManager() { - return mock(PlatformTransactionManager.class); - } - - } - - @Configuration - @EnableJdbcHttpSession - static class DefaultConfiguration extends BaseConfiguration { - } - - @Configuration - @EnableJdbcHttpSession(tableName = TABLE_NAME) - static class CustomTableNameConfiguration extends BaseConfiguration { - } - - @Configuration - static class CustomTableNameSetConfiguration extends JdbcHttpSessionConfiguration { - - CustomTableNameSetConfiguration() { - setTableName("custom_session"); - } - - } - - @Configuration - static class CustomMaxInactiveIntervalInSecondsSetConfiguration extends JdbcHttpSessionConfiguration { - - CustomMaxInactiveIntervalInSecondsSetConfiguration() { - setMaxInactiveIntervalInSeconds(10); - } - - } - - @Configuration - @EnableJdbcHttpSession(maxInactiveIntervalInSeconds = MAX_INACTIVE_INTERVAL_IN_SECONDS) - static class CustomMaxInactiveIntervalInSecondsConfiguration - extends BaseConfiguration { - } - - @Configuration - @EnableJdbcHttpSession - static class CustomLobHandlerConfiguration extends BaseConfiguration { - - @Bean - public LobHandler springSessionLobHandler() { - return mock(LobHandler.class); - } - - } - - @Configuration - @EnableJdbcHttpSession - static class CustomConversionServiceConfiguration extends BaseConfiguration { - - @Bean - public ConversionService springSessionConversionService() { - return mock(ConversionService.class); - } - - } - - @Configuration - @EnableJdbcHttpSession(tableName = "${session.jdbc.tableName}") - static class CustomJdbcHttpSessionConfiguration extends BaseConfiguration { - - @Bean - public PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() { - return new PropertySourcesPlaceholderConfigurer(); - } - - } - -} diff --git a/spring-session/src/test/java/org/springframework/session/security/SpringSessionBackedSessionRegistryTest.java b/spring-session/src/test/java/org/springframework/session/security/SpringSessionBackedSessionRegistryTest.java deleted file mode 100644 index 721f5e7..0000000 --- a/spring-session/src/test/java/org/springframework/session/security/SpringSessionBackedSessionRegistryTest.java +++ /dev/null @@ -1,149 +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.security; - -import java.util.Collections; -import java.util.Date; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; - -import org.springframework.security.core.Authentication; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.context.SecurityContextImpl; -import org.springframework.security.core.session.SessionInformation; -import org.springframework.security.core.userdetails.User; -import org.springframework.session.ExpiringSession; -import org.springframework.session.FindByIndexNameSessionRepository; -import org.springframework.session.MapSession; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.BDDMockito.mock; -import static org.mockito.BDDMockito.verify; -import static org.mockito.BDDMockito.when; - -@RunWith(MockitoJUnitRunner.class) -public class SpringSessionBackedSessionRegistryTest { - - static final String SESSION_ID = "sessionId"; - static final String SESSION_ID2 = "otherSessionId"; - static final String USER_NAME = "userName"; - static final User PRINCIPAL = new User(USER_NAME, "password", Collections.emptyList()); - static final Date NOW = new Date(); - - @Mock - FindByIndexNameSessionRepository sessionRepository; - - @InjectMocks - SpringSessionBackedSessionRegistry sessionRegistry; - - @Test - public void sessionInformationForExistingSession() { - ExpiringSession session = createSession(SESSION_ID, USER_NAME, NOW.getTime()); - when(this.sessionRepository.getSession(SESSION_ID)).thenReturn(session); - - SessionInformation sessionInfo = this.sessionRegistry.getSessionInformation(SESSION_ID); - - assertThat(sessionInfo.getSessionId()).isEqualTo(SESSION_ID); - assertThat(sessionInfo.getLastRequest()).isEqualTo(NOW); - assertThat(sessionInfo.getPrincipal()).isEqualTo(USER_NAME); - assertThat(sessionInfo.isExpired()).isFalse(); - } - - @Test - public void sessionInformationForExpiredSession() { - ExpiringSession session = createSession(SESSION_ID, USER_NAME, NOW.getTime()); - session.setAttribute(SpringSessionBackedSessionInformation.EXPIRED_ATTR, Boolean.TRUE); - when(this.sessionRepository.getSession(SESSION_ID)).thenReturn(session); - - SessionInformation sessionInfo = this.sessionRegistry.getSessionInformation(SESSION_ID); - - assertThat(sessionInfo.getSessionId()).isEqualTo(SESSION_ID); - assertThat(sessionInfo.getLastRequest()).isEqualTo(NOW); - assertThat(sessionInfo.getPrincipal()).isEqualTo(USER_NAME); - assertThat(sessionInfo.isExpired()).isTrue(); - } - - @Test - public void noSessionInformationForMissingSession() { - assertThat(this.sessionRegistry.getSessionInformation("nonExistingSessionId")).isNull(); - } - - @Test - public void getAllSessions() { - setUpSessions(); - - List allSessionInfos = this.sessionRegistry.getAllSessions(PRINCIPAL, true); - - assertThat(allSessionInfos).extracting("sessionId").containsExactly(SESSION_ID, SESSION_ID2); - } - - @Test - public void getNonExpiredSessions() { - setUpSessions(); - - List nonExpiredSessionInfos = this.sessionRegistry.getAllSessions(PRINCIPAL, false); - - assertThat(nonExpiredSessionInfos).extracting("sessionId").containsExactly(SESSION_ID2); - } - - @Test - public void expireNow() { - ExpiringSession session = createSession(SESSION_ID, USER_NAME, NOW.getTime()); - when(this.sessionRepository.getSession(SESSION_ID)).thenReturn(session); - - SessionInformation sessionInfo = this.sessionRegistry.getSessionInformation(SESSION_ID); - assertThat(sessionInfo.isExpired()).isFalse(); - - sessionInfo.expireNow(); - - assertThat(sessionInfo.isExpired()).isTrue(); - ArgumentCaptor captor = ArgumentCaptor.forClass(ExpiringSession.class); - verify(this.sessionRepository).save(captor.capture()); - assertThat(captor.getValue().getAttribute(SpringSessionBackedSessionInformation.EXPIRED_ATTR)) - .isEqualTo(Boolean.TRUE); - } - - private ExpiringSession createSession(String sessionId, String userName, Long lastAccessed) { - MapSession session = new MapSession(sessionId); - session.setLastAccessedTime(lastAccessed); - Authentication authentication = mock(Authentication.class); - when(authentication.getName()).thenReturn(userName); - SecurityContextImpl securityContext = new SecurityContextImpl(); - securityContext.setAuthentication(authentication); - session.setAttribute("SPRING_SECURITY_CONTEXT", securityContext); - return session; - } - - private void setUpSessions() { - ExpiringSession session1 = createSession(SESSION_ID, USER_NAME, NOW.getTime()); - session1.setAttribute(SpringSessionBackedSessionInformation.EXPIRED_ATTR, Boolean.TRUE); - ExpiringSession session2 = createSession(SESSION_ID2, USER_NAME, NOW.getTime()); - Map sessions = new LinkedHashMap(); - sessions.put(session1.getId(), session1); - sessions.put(session2.getId(), session2); - when(this.sessionRepository.findByIndexNameAndIndexValue(FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, USER_NAME)).thenReturn(sessions); - } - -} diff --git a/spring-session/src/test/java/org/springframework/session/security/web/authentication/SpringSessionRememberMeServicesTests.java b/spring-session/src/test/java/org/springframework/session/security/web/authentication/SpringSessionRememberMeServicesTests.java deleted file mode 100644 index 6e90206..0000000 --- a/spring-session/src/test/java/org/springframework/session/security/web/authentication/SpringSessionRememberMeServicesTests.java +++ /dev/null @@ -1,194 +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.security.web.authentication; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; - -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -import org.springframework.security.core.Authentication; -import org.springframework.security.web.context.HttpSessionSecurityContextRepository; -import org.springframework.test.util.ReflectionTestUtils; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; - -/** - * Tests for {@link SpringSessionRememberMeServices}. - * - * @author Vedran Pavic - */ -public class SpringSessionRememberMeServicesTests { - - @Rule - public ExpectedException thrown = ExpectedException.none(); - - private SpringSessionRememberMeServices rememberMeServices; - - @Test - public void create() { - this.rememberMeServices = new SpringSessionRememberMeServices(); - assertThat(ReflectionTestUtils.getField(this.rememberMeServices, - "rememberMeParameterName")).isEqualTo("remember-me"); - assertThat( - ReflectionTestUtils.getField(this.rememberMeServices, "alwaysRemember")) - .isEqualTo(false); - assertThat( - ReflectionTestUtils.getField(this.rememberMeServices, "validitySeconds")) - .isEqualTo(2592000); - } - - @Test - public void createWithCustomParameter() { - this.rememberMeServices = new SpringSessionRememberMeServices(); - this.rememberMeServices.setRememberMeParameterName("test-param"); - assertThat(ReflectionTestUtils.getField(this.rememberMeServices, - "rememberMeParameterName")).isEqualTo("test-param"); - } - - @Test - public void createWithNullParameter() { - this.thrown.expect(IllegalArgumentException.class); - this.thrown.expectMessage("rememberMeParameterName cannot be empty or null"); - this.rememberMeServices = new SpringSessionRememberMeServices(); - this.rememberMeServices.setRememberMeParameterName(null); - } - - @Test - public void createWithAlwaysRemember() { - this.rememberMeServices = new SpringSessionRememberMeServices(); - this.rememberMeServices.setAlwaysRemember(true); - assertThat( - ReflectionTestUtils.getField(this.rememberMeServices, "alwaysRemember")) - .isEqualTo(true); - } - - @Test - public void createWithCustomValidity() { - this.rememberMeServices = new SpringSessionRememberMeServices(); - this.rememberMeServices.setValiditySeconds(100000); - assertThat( - ReflectionTestUtils.getField(this.rememberMeServices, "validitySeconds")) - .isEqualTo(100000); - } - - @Test - public void autoLogin() { - HttpServletRequest request = mock(HttpServletRequest.class); - HttpServletResponse response = mock(HttpServletResponse.class); - this.rememberMeServices = new SpringSessionRememberMeServices(); - this.rememberMeServices.autoLogin(request, response); - verifyZeroInteractions(request, response); - } - - // gh-752 - @Test - public void loginFailRemoveSecurityContext() { - HttpServletRequest request = mock(HttpServletRequest.class); - HttpServletResponse response = mock(HttpServletResponse.class); - HttpSession session = mock(HttpSession.class); - given(request.getSession(eq(false))).willReturn(session); - this.rememberMeServices = new SpringSessionRememberMeServices(); - this.rememberMeServices.loginFail(request, response); - verify(request, times(1)).getSession(eq(false)); - verify(session, times(1)).removeAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY); - verifyZeroInteractions(request, response, session); - } - - @Test - public void loginSuccess() { - HttpServletRequest request = mock(HttpServletRequest.class); - HttpServletResponse response = mock(HttpServletResponse.class); - Authentication authentication = mock(Authentication.class); - HttpSession session = mock(HttpSession.class); - given(request.getParameter(eq("remember-me"))).willReturn("true"); - given(request.getSession()).willReturn(session); - this.rememberMeServices = new SpringSessionRememberMeServices(); - this.rememberMeServices.loginSuccess(request, response, authentication); - verify(request, times(1)).getParameter(eq("remember-me")); - verify(request, times(1)).getSession(); - verify(request, times(1)).setAttribute( - eq(SpringSessionRememberMeServices.REMEMBER_ME_LOGIN_ATTR), eq(true)); - verify(session, times(1)).setMaxInactiveInterval(eq(2592000)); - verifyZeroInteractions(request, response, session, authentication); - } - - @Test - public void loginSuccessWithCustomParameter() { - HttpServletRequest request = mock(HttpServletRequest.class); - HttpServletResponse response = mock(HttpServletResponse.class); - Authentication authentication = mock(Authentication.class); - HttpSession session = mock(HttpSession.class); - given(request.getParameter(eq("test-param"))).willReturn("true"); - given(request.getSession()).willReturn(session); - this.rememberMeServices = new SpringSessionRememberMeServices(); - this.rememberMeServices.setRememberMeParameterName("test-param"); - this.rememberMeServices.loginSuccess(request, response, authentication); - verify(request, times(1)).getParameter(eq("test-param")); - verify(request, times(1)).getSession(); - verify(request, times(1)).setAttribute( - eq(SpringSessionRememberMeServices.REMEMBER_ME_LOGIN_ATTR), eq(true)); - verify(session, times(1)).setMaxInactiveInterval(eq(2592000)); - verifyZeroInteractions(request, response, session, authentication); - } - - @Test - public void loginSuccessWithAlwaysRemember() { - HttpServletRequest request = mock(HttpServletRequest.class); - HttpServletResponse response = mock(HttpServletResponse.class); - Authentication authentication = mock(Authentication.class); - HttpSession session = mock(HttpSession.class); - given(request.getSession()).willReturn(session); - this.rememberMeServices = new SpringSessionRememberMeServices(); - this.rememberMeServices.setAlwaysRemember(true); - this.rememberMeServices.loginSuccess(request, response, authentication); - verify(request, times(1)).getSession(); - verify(request, times(1)).setAttribute( - eq(SpringSessionRememberMeServices.REMEMBER_ME_LOGIN_ATTR), eq(true)); - verify(session, times(1)).setMaxInactiveInterval(eq(2592000)); - verifyZeroInteractions(request, response, session, authentication); - } - - @Test - public void loginSuccessWithCustomValidity() { - HttpServletRequest request = mock(HttpServletRequest.class); - HttpServletResponse response = mock(HttpServletResponse.class); - Authentication authentication = mock(Authentication.class); - HttpSession session = mock(HttpSession.class); - given(request.getParameter(eq("remember-me"))).willReturn("true"); - given(request.getSession()).willReturn(session); - this.rememberMeServices = new SpringSessionRememberMeServices(); - this.rememberMeServices.setValiditySeconds(100000); - this.rememberMeServices.loginSuccess(request, response, authentication); - verify(request, times(1)).getParameter(eq("remember-me")); - verify(request, times(1)).getSession(); - verify(request, times(1)).setAttribute( - eq(SpringSessionRememberMeServices.REMEMBER_ME_LOGIN_ATTR), eq(true)); - verify(session, times(1)).setMaxInactiveInterval(eq(100000)); - verifyZeroInteractions(request, response, session, authentication); - } - -} diff --git a/spring-session/src/test/java/org/springframework/session/web/http/CookieHttpSessionStrategyTests.java b/spring-session/src/test/java/org/springframework/session/web/http/CookieHttpSessionStrategyTests.java deleted file mode 100644 index 3a84c04..0000000 --- a/spring-session/src/test/java/org/springframework/session/web/http/CookieHttpSessionStrategyTests.java +++ /dev/null @@ -1,746 +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.web.http; - -import java.util.Base64; -import java.util.Map; - -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletResponse; - -import org.junit.Before; -import org.junit.Test; - -import org.springframework.mock.web.MockHttpServletRequest; -import org.springframework.mock.web.MockHttpServletResponse; -import org.springframework.session.MapSession; -import org.springframework.session.Session; - -import static org.assertj.core.api.Assertions.assertThat; - -public class CookieHttpSessionStrategyTests { - private MockHttpServletRequest request; - private MockHttpServletResponse response; - - private CookieHttpSessionStrategy strategy; - private String cookieName; - private Session session; - - @Before - public void setup() throws Exception { - this.cookieName = "SESSION"; - this.session = new MapSession(); - this.request = new MockHttpServletRequest(); - this.response = new MockHttpServletResponse(); - this.strategy = new CookieHttpSessionStrategy(); - } - - @Test - public void getRequestedSessionIdNull() throws Exception { - assertThat(this.strategy.getRequestedSessionId(this.request)).isNull(); - } - - @Test - public void getRequestedSessionIdNotNull() throws Exception { - setSessionCookie(this.session.getId()); - assertThat(this.strategy.getRequestedSessionId(this.request)) - .isEqualTo(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()); - } - - @Test - public void onNewSession() throws Exception { - this.strategy.onNewSession(this.session, this.request, this.response); - assertThat(getSessionId()).isEqualTo(this.session.getId()); - } - - @Test - public void onNewSessionTwiceSameId() throws Exception { - this.strategy.onNewSession(this.session, this.request, this.response); - this.strategy.onNewSession(this.session, this.request, this.response); - - assertThat(this.response.getCookies()).hasSize(1); - } - - @Test - public void onNewSessionTwiceNewId() throws Exception { - Session newSession = new MapSession(); - - this.strategy.onNewSession(this.session, this.request, this.response); - this.strategy.onNewSession(newSession, this.request, this.response); - - Cookie[] cookies = this.response.getCookies(); - assertThat(cookies).hasSize(2); - - assertThat(base64Decode(cookies[0].getValue())).isEqualTo(this.session.getId()); - 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"); - this.strategy.onNewSession(this.session, this.request, this.response); - - Cookie sessionCookie = this.response.getCookie(this.cookieName); - assertThat(sessionCookie.getPath()) - .isEqualTo(this.request.getContextPath() + "/"); - } - - @Test - public void onNewSessionCustomCookieName() throws Exception { - setCookieName("CUSTOM"); - this.strategy.onNewSession(this.session, this.request, this.response); - assertThat(getSessionId()).isEqualTo(this.session.getId()); - } - - @Test - public void onDeleteSession() throws Exception { - this.strategy.onInvalidateSession(this.request, this.response); - assertThat(getSessionId()).isEmpty(); - } - - @Test - public void onDeleteSessionCookiePath() throws Exception { - this.request.setContextPath("/somethingunique"); - this.strategy.onInvalidateSession(this.request, this.response); - - Cookie sessionCookie = this.response.getCookie(this.cookieName); - assertThat(sessionCookie.getPath()) - .isEqualTo(this.request.getContextPath() + "/"); - } - - @Test - public void onDeleteSessionCustomCookieName() throws Exception { - setCookieName("CUSTOM"); - this.strategy.onInvalidateSession(this.request, this.response); - 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) { - StringBuffer buffer = new StringBuffer(); - - for (long i = 0; i < size; i++) { - String hex = Long.toHexString(i); - buffer.append(hex); - buffer.append(" "); - buffer.append(i); - if (i < size - 1) { - buffer.append(" "); - } - } - - return buffer.toString(); - } - - public void setCookieName(String cookieName) { - DefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer(); - cookieSerializer.setCookieName(cookieName); - this.strategy.setCookieSerializer(cookieSerializer); - this.cookieName = cookieName; - } - - public void setSessionCookie(String value) { - this.request.setCookies(new Cookie(this.cookieName, base64Encode(value))); - } - - public String getSessionId() { - return base64Decode(this.response.getCookie(this.cookieName).getValue()); - } - - private static String base64Encode(String value) { - return Base64.getEncoder().encodeToString(value.getBytes()); - } - - private static String base64Decode(String value) { - return new String(Base64.getDecoder().decode(value)); - } - -} diff --git a/spring-session/src/test/java/org/springframework/session/web/http/DefaultCookieSerializerTests.java b/spring-session/src/test/java/org/springframework/session/web/http/DefaultCookieSerializerTests.java deleted file mode 100644 index f83d3b4..0000000 --- a/spring-session/src/test/java/org/springframework/session/web/http/DefaultCookieSerializerTests.java +++ /dev/null @@ -1,477 +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.Base64; - -import javax.servlet.http.Cookie; - -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; - -import org.springframework.mock.web.MockHttpServletRequest; -import org.springframework.mock.web.MockHttpServletResponse; -import org.springframework.session.web.http.CookieSerializer.CookieValue; -import org.springframework.util.StringUtils; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Tests for {@link DefaultCookieSerializer}. - * - * @author Rob Winch - * @author Vedran Pavic - * @author Eddú Meléndez - */ -@RunWith(Parameterized.class) -public class DefaultCookieSerializerTests { - - @Parameters(name = "useBase64Encoding={0}") - public static Object[] parameters() { - return new Object[] { false, true }; - } - - @Rule - public ExpectedException thrown = ExpectedException.none(); - - private boolean useBase64Encoding; - - private String cookieName; - - private MockHttpServletRequest request; - - private MockHttpServletResponse response; - - private DefaultCookieSerializer serializer; - - private String sessionId; - - public DefaultCookieSerializerTests(boolean useBase64Encoding) { - this.useBase64Encoding = useBase64Encoding; - } - - @Before - public void setup() { - this.cookieName = "SESSION"; - this.request = new MockHttpServletRequest(); - this.response = new MockHttpServletResponse(); - this.sessionId = "sessionId"; - this.serializer = new DefaultCookieSerializer(); - this.serializer.setUseBase64Encoding(this.useBase64Encoding); - } - - // --- readCookieValues --- - - @Test - public void readCookieValuesNull() { - assertThat(this.serializer.readCookieValues(this.request)).isEmpty(); - } - - @Test - public void readCookieValuesSingle() { - this.request.setCookies(createCookie(this.cookieName, this.sessionId)); - - assertThat(this.serializer.readCookieValues(this.request)) - .containsOnly(this.sessionId); - } - - @Test - public void readCookieSerializerUseBase64EncodingTrueValuesNotBase64() { - this.sessionId = "&^%$*"; - this.serializer.setUseBase64Encoding(true); - this.request.setCookies(new Cookie(this.cookieName, this.sessionId)); - - assertThat(this.serializer.readCookieValues(this.request)).isEmpty(); - } - - @Test - public void readCookieValuesSingleAndInvalidName() { - this.request.setCookies(createCookie(this.cookieName, this.sessionId), - createCookie(this.cookieName + "INVALID", this.sessionId + "INVALID")); - - assertThat(this.serializer.readCookieValues(this.request)) - .containsOnly(this.sessionId); - } - - @Test - public void readCookieValuesMulti() { - String secondSession = "secondSessionId"; - this.request.setCookies(createCookie(this.cookieName, this.sessionId), - createCookie(this.cookieName, secondSession)); - - assertThat(this.serializer.readCookieValues(this.request)) - .containsExactly(this.sessionId, secondSession); - } - - @Test - public void readCookieValuesMultiCustomSessionCookieName() { - setCookieName("JSESSIONID"); - String secondSession = "secondSessionId"; - this.request.setCookies(createCookie(this.cookieName, this.sessionId), - createCookie(this.cookieName, secondSession)); - - assertThat(this.serializer.readCookieValues(this.request)) - .containsExactly(this.sessionId, secondSession); - } - - // gh-392 - @Test - public void readCookieValuesNullCookieValue() { - this.request.setCookies(createCookie(this.cookieName, null)); - - assertThat(this.serializer.readCookieValues(this.request)).isEmpty(); - } - - @Test - public void readCookieValuesNullCookieValueAndJvmRoute() { - this.serializer.setJvmRoute("123"); - this.request.setCookies(createCookie(this.cookieName, null)); - - assertThat(this.serializer.readCookieValues(this.request)).isEmpty(); - } - - @Test - public void readCookieValuesNullCookieValueAndNotNullCookie() { - this.serializer.setJvmRoute("123"); - this.request.setCookies(createCookie(this.cookieName, null), - createCookie(this.cookieName, this.sessionId)); - - assertThat(this.serializer.readCookieValues(this.request)) - .containsOnly(this.sessionId); - } - - // --- writeCookie --- - - @Test - public void writeCookie() { - this.serializer.writeCookieValue(cookieValue(this.sessionId)); - - assertThat(getCookieValue()).isEqualTo(this.sessionId); - } - - // --- httpOnly --- - - @Test - public void writeCookieHttpOnlyDefault() { - this.serializer.writeCookieValue(cookieValue(this.sessionId)); - - assertThat(getCookie().isHttpOnly()).isTrue(); - } - - @Test - public void writeCookieHttpOnlySetTrue() { - this.serializer.setUseHttpOnlyCookie(true); - - this.serializer.writeCookieValue(cookieValue(this.sessionId)); - - assertThat(getCookie().isHttpOnly()).isTrue(); - } - - @Test - public void writeCookieHttpOnlySetFalse() { - this.serializer.setUseHttpOnlyCookie(false); - - this.serializer.writeCookieValue(cookieValue(this.sessionId)); - - assertThat(getCookie().isHttpOnly()).isFalse(); - } - - // --- domainName --- - - @Test - public void writeCookieDomainNameDefault() { - this.serializer.writeCookieValue(cookieValue(this.sessionId)); - - assertThat(getCookie().getDomain()).isNull(); - } - - @Test - public void writeCookieDomainNameCustom() { - String domainName = "example.com"; - this.serializer.setDomainName(domainName); - - this.serializer.writeCookieValue(cookieValue(this.sessionId)); - - assertThat(getCookie().getDomain()).isEqualTo(domainName); - } - - @Test(expected = IllegalStateException.class) - public void setDomainNameAndDomainNamePatternThrows() { - this.serializer.setDomainName("example.com"); - this.serializer.setDomainNamePattern(".*"); - } - - // --- domainNamePattern --- - - @Test - public void writeCookieDomainNamePattern() { - String domainNamePattern = "^.+?\\.(\\w+\\.[a-z]+)$"; - this.serializer.setDomainNamePattern(domainNamePattern); - - String[] matchingDomains = { "child.sub.example.com", "www.example.com" }; - for (String domain : matchingDomains) { - this.request.setServerName(domain); - this.serializer.writeCookieValue(cookieValue(this.sessionId)); - assertThat(getCookie().getDomain()).isEqualTo("example.com"); - - this.response = new MockHttpServletResponse(); - } - - String[] notMatchingDomains = { "example.com", "localhost", "127.0.0.1" }; - for (String domain : notMatchingDomains) { - this.request.setServerName(domain); - this.serializer.writeCookieValue(cookieValue(this.sessionId)); - assertThat(getCookie().getDomain()).isNull(); - - this.response = new MockHttpServletResponse(); - } - } - - @Test(expected = IllegalStateException.class) - public void setDomainNamePatternAndDomainNameThrows() { - this.serializer.setDomainNamePattern(".*"); - this.serializer.setDomainName("example.com"); - } - - // --- cookieName --- - - @Test - public void writeCookieCookieNameDefault() { - this.serializer.writeCookieValue(cookieValue(this.sessionId)); - - assertThat(getCookie().getName()).isEqualTo("SESSION"); - } - - @Test - public void writeCookieCookieNameCustom() { - String cookieName = "JSESSIONID"; - setCookieName(cookieName); - - this.serializer.writeCookieValue(cookieValue(this.sessionId)); - - assertThat(getCookie().getName()).isEqualTo(cookieName); - } - - @Test(expected = IllegalArgumentException.class) - public void setCookieNameNullThrows() { - this.serializer.setCookieName(null); - } - - // --- cookiePath --- - - @Test - public void writeCookieCookiePathDefaultEmptyContextPathUsed() { - this.request.setContextPath(""); - - this.serializer.writeCookieValue(cookieValue(this.sessionId)); - - assertThat(getCookie().getPath()).isEqualTo("/"); - } - - @Test - public void writeCookieCookiePathDefaultContextPathUsed() { - this.request.setContextPath("/context"); - - this.serializer.writeCookieValue(cookieValue(this.sessionId)); - - assertThat(getCookie().getPath()).isEqualTo("/context/"); - } - - @Test - public void writeCookieCookiePathExplicitNullCookiePathContextPathUsed() { - this.request.setContextPath("/context"); - this.serializer.setCookiePath(null); - - this.serializer.writeCookieValue(cookieValue(this.sessionId)); - - assertThat(getCookie().getPath()).isEqualTo("/context/"); - } - - @Test - public void writeCookieCookiePathExplicitCookiePath() { - this.request.setContextPath("/context"); - this.serializer.setCookiePath("/"); - - this.serializer.writeCookieValue(cookieValue(this.sessionId)); - - assertThat(getCookie().getPath()).isEqualTo("/"); - } - - // --- cookieMaxAge --- - - @Test - public void writeCookieCookieMaxAgeDefault() { - this.serializer.writeCookieValue(cookieValue(this.sessionId)); - - assertThat(getCookie().getMaxAge()).isEqualTo(-1); - } - - @Test - public void writeCookieCookieMaxAgeExplicit() { - this.serializer.setCookieMaxAge(100); - - this.serializer.writeCookieValue(cookieValue(this.sessionId)); - - assertThat(getCookie().getMaxAge()).isEqualTo(100); - } - - @Test - public void writeCookieCookieMaxAgeExplicitEmptyCookie() { - this.serializer.setCookieMaxAge(100); - - this.serializer.writeCookieValue(cookieValue("")); - - assertThat(getCookie().getMaxAge()).isEqualTo(0); - } - - // --- secure --- - - @Test - public void writeCookieDefaultInsecureRequest() { - this.serializer.writeCookieValue(cookieValue(this.sessionId)); - - assertThat(getCookie().getSecure()).isFalse(); - } - - @Test - public void writeCookieSecureSecureRequest() { - this.request.setSecure(true); - this.serializer.setUseSecureCookie(true); - - this.serializer.writeCookieValue(cookieValue(this.sessionId)); - - assertThat(getCookie().getSecure()).isTrue(); - } - - @Test - public void writeCookieSecureInsecureRequest() { - this.serializer.setUseSecureCookie(true); - - this.serializer.writeCookieValue(cookieValue(this.sessionId)); - - assertThat(getCookie().getSecure()).isTrue(); - } - - @Test - public void writeCookieInsecureSecureRequest() { - this.request.setSecure(true); - this.serializer.setUseSecureCookie(false); - - this.serializer.writeCookieValue(cookieValue(this.sessionId)); - - assertThat(getCookie().getSecure()).isFalse(); - } - - @Test - public void writeCookieInecureInsecureRequest() { - this.serializer.setUseSecureCookie(false); - - this.serializer.writeCookieValue(cookieValue(this.sessionId)); - - assertThat(getCookie().getSecure()).isFalse(); - } - - // --- jvmRoute --- - - @Test - public void writeCookieJvmRoute() { - String jvmRoute = "route"; - this.serializer.setJvmRoute(jvmRoute); - - this.serializer.writeCookieValue(cookieValue(this.sessionId)); - - assertThat(getCookieValue()).isEqualTo(this.sessionId + "." + jvmRoute); - } - - @Test - public void readCookieJvmRoute() { - String jvmRoute = "route"; - this.serializer.setJvmRoute(jvmRoute); - this.request.setCookies( - createCookie(this.cookieName, this.sessionId + "." + jvmRoute)); - - assertThat(this.serializer.readCookieValues(this.request)) - .containsOnly(this.sessionId); - } - - @Test - public void readCookieJvmRouteRouteMissing() { - String jvmRoute = "route"; - this.serializer.setJvmRoute(jvmRoute); - this.request.setCookies(createCookie(this.cookieName, this.sessionId)); - - assertThat(this.serializer.readCookieValues(this.request)) - .containsOnly(this.sessionId); - } - - @Test - public void readCookieJvmRouteOnlyRoute() { - String jvmRoute = "route"; - this.serializer.setJvmRoute(jvmRoute); - this.request.setCookies(createCookie(this.cookieName, "." + jvmRoute)); - - assertThat(this.serializer.readCookieValues(this.request)).containsOnly(""); - } - - // --- rememberMe --- - - @Test - public void writeCookieRememberMeCookieMaxAgeDefault() { - this.request.setAttribute("rememberMe", true); - this.serializer.setRememberMeRequestAttribute("rememberMe"); - this.serializer.writeCookieValue(cookieValue(this.sessionId)); - - assertThat(getCookie().getMaxAge()).isEqualTo(Integer.MAX_VALUE); - } - - public void setCookieName(String cookieName) { - this.cookieName = cookieName; - this.serializer.setCookieName(cookieName); - } - - private Cookie createCookie(String name, String value) { - if (this.useBase64Encoding && StringUtils.hasLength(value)) { - value = new String(Base64.getEncoder().encode(value.getBytes())); - } - return new Cookie(name, value); - } - - private Cookie getCookie() { - return this.response.getCookie(this.cookieName); - } - - private String getCookieValue() { - String value = getCookie().getValue(); - if (!this.useBase64Encoding) { - return value; - } - if (value == null) { - return null; - } - return new String(Base64.getDecoder().decode(value)); - } - - private CookieValue cookieValue(String cookieValue) { - return new CookieValue(this.request, this.response, cookieValue); - } - -} diff --git a/spring-session/src/test/java/org/springframework/session/web/http/HeaderSessionStrategyTests.java b/spring-session/src/test/java/org/springframework/session/web/http/HeaderSessionStrategyTests.java deleted file mode 100644 index 91eaafc..0000000 --- a/spring-session/src/test/java/org/springframework/session/web/http/HeaderSessionStrategyTests.java +++ /dev/null @@ -1,132 +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.web.http; - -import org.junit.Before; -import org.junit.Test; - -import org.springframework.mock.web.MockHttpServletRequest; -import org.springframework.mock.web.MockHttpServletResponse; -import org.springframework.session.MapSession; -import org.springframework.session.Session; - -import static org.assertj.core.api.Assertions.assertThat; - -public class HeaderSessionStrategyTests { - - private MockHttpServletRequest request; - private MockHttpServletResponse response; - - private HeaderHttpSessionStrategy strategy; - private String headerName; - private Session session; - - @Before - public void setup() throws Exception { - this.headerName = "X-Auth-Token"; - this.session = new MapSession(); - this.request = new MockHttpServletRequest(); - this.response = new MockHttpServletResponse(); - this.strategy = new HeaderHttpSessionStrategy(); - } - - @Test - public void getRequestedSessionIdNull() throws Exception { - assertThat(this.strategy.getRequestedSessionId(this.request)).isNull(); - } - - @Test - public void getRequestedSessionIdNotNull() throws Exception { - setSessionId(this.session.getId()); - assertThat(this.strategy.getRequestedSessionId(this.request)) - .isEqualTo(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()); - } - - @Test - public void onNewSession() throws Exception { - this.strategy.onNewSession(this.session, this.request, this.response); - assertThat(getSessionId()).isEqualTo(this.session.getId()); - } - - // the header is set as apposed to added - @Test - public void onNewSessionMulti() throws Exception { - this.strategy.onNewSession(this.session, this.request, this.response); - this.strategy.onNewSession(this.session, this.request, this.response); - - assertThat(this.response.getHeaders(this.headerName).size()).isEqualTo(1); - assertThat(this.response.getHeaders(this.headerName)) - .containsOnly(this.session.getId()); - } - - @Test - public void onNewSessionCustomHeaderName() throws Exception { - setHeaderName("CUSTOM"); - this.strategy.onNewSession(this.session, this.request, this.response); - assertThat(getSessionId()).isEqualTo(this.session.getId()); - } - - @Test - public void onDeleteSession() throws Exception { - this.strategy.onInvalidateSession(this.request, this.response); - assertThat(getSessionId()).isEmpty(); - } - - // the header is set as apposed to added - @Test - public void onDeleteSessionMulti() throws Exception { - this.strategy.onInvalidateSession(this.request, this.response); - this.strategy.onInvalidateSession(this.request, this.response); - - assertThat(this.response.getHeaders(this.headerName).size()).isEqualTo(1); - assertThat(getSessionId()).isEmpty(); - } - - @Test - public void onDeleteSessionCustomHeaderName() throws Exception { - setHeaderName("CUSTOM"); - this.strategy.onInvalidateSession(this.request, this.response); - assertThat(getSessionId()).isEmpty(); - } - - @Test(expected = IllegalArgumentException.class) - public void setHeaderNameNull() throws Exception { - this.strategy.setHeaderName(null); - } - - public void setHeaderName(String headerName) { - this.strategy.setHeaderName(headerName); - this.headerName = headerName; - } - - public void setSessionId(String id) { - this.request.addHeader(this.headerName, id); - } - - public String getSessionId() { - return this.response.getHeader(this.headerName); - } - -} diff --git a/spring-session/src/test/java/org/springframework/session/web/http/OnCommittedResponseWrapperTests.java b/spring-session/src/test/java/org/springframework/session/web/http/OnCommittedResponseWrapperTests.java deleted file mode 100644 index 23ca44c..0000000 --- a/spring-session/src/test/java/org/springframework/session/web/http/OnCommittedResponseWrapperTests.java +++ /dev/null @@ -1,1120 +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.web.http; - -import java.io.IOException; -import java.io.PrintWriter; -import java.util.Locale; - -import javax.servlet.ServletOutputStream; -import javax.servlet.http.HttpServletResponse; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.verify; - -@RunWith(MockitoJUnitRunner.class) -public class OnCommittedResponseWrapperTests { - private static final String NL = "\r\n"; - - @Mock - HttpServletResponse delegate; - @Mock - PrintWriter writer; - @Mock - ServletOutputStream out; - - OnCommittedResponseWrapper response; - - boolean committed; - - @Before - public void setup() throws Exception { - this.response = new OnCommittedResponseWrapper(this.delegate) { - @Override - protected void onResponseCommitted() { - OnCommittedResponseWrapperTests.this.committed = true; - } - }; - given(this.delegate.getWriter()).willReturn(this.writer); - given(this.delegate.getOutputStream()).willReturn(this.out); - } - - // --- printwriter - - @Test - public void printWriterHashCode() throws Exception { - int expected = this.writer.hashCode(); - - assertThat(this.response.getWriter().hashCode()).isEqualTo(expected); - } - - @Test - public void printWriterCheckError() throws Exception { - boolean expected = true; - given(this.writer.checkError()).willReturn(expected); - - assertThat(this.response.getWriter().checkError()).isEqualTo(expected); - } - - @Test - public void printWriterWriteInt() throws Exception { - int expected = 1; - - this.response.getWriter().write(expected); - - verify(this.writer).write(expected); - } - - @Test - public void printWriterWriteCharIntInt() throws Exception { - char[] buff = new char[0]; - int off = 2; - int len = 3; - - this.response.getWriter().write(buff, off, len); - - verify(this.writer).write(buff, off, len); - } - - @Test - public void printWriterWriteChar() throws Exception { - char[] buff = new char[0]; - - this.response.getWriter().write(buff); - - verify(this.writer).write(buff); - } - - @Test - public void printWriterWriteStringIntInt() throws Exception { - String s = ""; - int off = 2; - int len = 3; - - this.response.getWriter().write(s, off, len); - - verify(this.writer).write(s, off, len); - } - - @Test - public void printWriterWriteString() throws Exception { - String s = ""; - - this.response.getWriter().write(s); - - verify(this.writer).write(s); - } - - @Test - public void printWriterPrintBoolean() throws Exception { - boolean b = true; - - this.response.getWriter().print(b); - - verify(this.writer).print(b); - } - - @Test - public void printWriterPrintChar() throws Exception { - char c = 1; - - this.response.getWriter().print(c); - - verify(this.writer).print(c); - } - - @Test - public void printWriterPrintInt() throws Exception { - int i = 1; - - this.response.getWriter().print(i); - - verify(this.writer).print(i); - } - - @Test - public void printWriterPrintLong() throws Exception { - long l = 1; - - this.response.getWriter().print(l); - - verify(this.writer).print(l); - } - - @Test - public void printWriterPrintFloat() throws Exception { - float f = 1; - - this.response.getWriter().print(f); - - verify(this.writer).print(f); - } - - @Test - public void printWriterPrintDouble() throws Exception { - double x = 1; - - this.response.getWriter().print(x); - - verify(this.writer).print(x); - } - - @Test - public void printWriterPrintCharArray() throws Exception { - char[] x = new char[0]; - - this.response.getWriter().print(x); - - verify(this.writer).print(x); - } - - @Test - public void printWriterPrintString() throws Exception { - String x = "1"; - - this.response.getWriter().print(x); - - verify(this.writer).print(x); - } - - @Test - public void printWriterPrintObject() throws Exception { - Object x = "1"; - - this.response.getWriter().print(x); - - verify(this.writer).print(x); - } - - @Test - public void printWriterPrintln() throws Exception { - this.response.getWriter().println(); - - verify(this.writer).println(); - } - - @Test - public void printWriterPrintlnBoolean() throws Exception { - boolean b = true; - - this.response.getWriter().println(b); - - verify(this.writer).println(b); - } - - @Test - public void printWriterPrintlnChar() throws Exception { - char c = 1; - - this.response.getWriter().println(c); - - verify(this.writer).println(c); - } - - @Test - public void printWriterPrintlnInt() throws Exception { - int i = 1; - - this.response.getWriter().println(i); - - verify(this.writer).println(i); - } - - @Test - public void printWriterPrintlnLong() throws Exception { - long l = 1; - - this.response.getWriter().println(l); - - verify(this.writer).println(l); - } - - @Test - public void printWriterPrintlnFloat() throws Exception { - float f = 1; - - this.response.getWriter().println(f); - - verify(this.writer).println(f); - } - - @Test - public void printWriterPrintlnDouble() throws Exception { - double x = 1; - - this.response.getWriter().println(x); - - verify(this.writer).println(x); - } - - @Test - public void printWriterPrintlnCharArray() throws Exception { - char[] x = new char[0]; - - this.response.getWriter().println(x); - - verify(this.writer).println(x); - } - - @Test - public void printWriterPrintlnString() throws Exception { - String x = "1"; - - this.response.getWriter().println(x); - - verify(this.writer).println(x); - } - - @Test - public void printWriterPrintlnObject() throws Exception { - Object x = "1"; - - this.response.getWriter().println(x); - - verify(this.writer).println(x); - } - - @Test - public void printWriterPrintfStringObjectVargs() throws Exception { - String format = "format"; - Object[] args = new Object[] { "1" }; - - this.response.getWriter().printf(format, args); - - verify(this.writer).printf(format, args); - } - - @Test - public void printWriterPrintfLocaleStringObjectVargs() throws Exception { - Locale l = Locale.US; - String format = "format"; - Object[] args = new Object[] { "1" }; - - this.response.getWriter().printf(l, format, args); - - verify(this.writer).printf(l, format, args); - } - - @Test - public void printWriterFormatStringObjectVargs() throws Exception { - String format = "format"; - Object[] args = new Object[] { "1" }; - - this.response.getWriter().format(format, args); - - verify(this.writer).format(format, args); - } - - @Test - public void printWriterFormatLocaleStringObjectVargs() throws Exception { - Locale l = Locale.US; - String format = "format"; - Object[] args = new Object[] { "1" }; - - this.response.getWriter().format(l, format, args); - - verify(this.writer).format(l, format, args); - } - - @Test - public void printWriterAppendCharSequence() throws Exception { - String x = "a"; - - this.response.getWriter().append(x); - - verify(this.writer).append(x); - } - - @Test - public void printWriterAppendCharSequenceIntInt() throws Exception { - String x = "abcdef"; - int start = 1; - int end = 3; - - this.response.getWriter().append(x, start, end); - - verify(this.writer).append(x, start, end); - } - - @Test - public void printWriterAppendChar() throws Exception { - char x = 1; - - this.response.getWriter().append(x); - - verify(this.writer).append(x); - } - - // servletoutputstream - - @Test - public void outputStreamHashCode() throws Exception { - int expected = this.out.hashCode(); - - assertThat(this.response.getOutputStream().hashCode()).isEqualTo(expected); - } - - @Test - public void outputStreamWriteInt() throws Exception { - int expected = 1; - - this.response.getOutputStream().write(expected); - - verify(this.out).write(expected); - } - - @Test - public void outputStreamWriteByte() throws Exception { - byte[] expected = new byte[0]; - - this.response.getOutputStream().write(expected); - - verify(this.out).write(expected); - } - - @Test - public void outputStreamWriteByteIntInt() throws Exception { - int start = 1; - int end = 2; - byte[] expected = new byte[0]; - - this.response.getOutputStream().write(expected, start, end); - - verify(this.out).write(expected, start, end); - } - - @Test - public void outputStreamPrintBoolean() throws Exception { - boolean b = true; - - this.response.getOutputStream().print(b); - - verify(this.out).print(b); - } - - @Test - public void outputStreamPrintChar() throws Exception { - char c = 1; - - this.response.getOutputStream().print(c); - - verify(this.out).print(c); - } - - @Test - public void outputStreamPrintInt() throws Exception { - int i = 1; - - this.response.getOutputStream().print(i); - - verify(this.out).print(i); - } - - @Test - public void outputStreamPrintLong() throws Exception { - long l = 1; - - this.response.getOutputStream().print(l); - - verify(this.out).print(l); - } - - @Test - public void outputStreamPrintFloat() throws Exception { - float f = 1; - - this.response.getOutputStream().print(f); - - verify(this.out).print(f); - } - - @Test - public void outputStreamPrintDouble() throws Exception { - double x = 1; - - this.response.getOutputStream().print(x); - - verify(this.out).print(x); - } - - @Test - public void outputStreamPrintString() throws Exception { - String x = "1"; - - this.response.getOutputStream().print(x); - - verify(this.out).print(x); - } - - @Test - public void outputStreamPrintln() throws Exception { - this.response.getOutputStream().println(); - - verify(this.out).println(); - } - - @Test - public void outputStreamPrintlnBoolean() throws Exception { - boolean b = true; - - this.response.getOutputStream().println(b); - - verify(this.out).println(b); - } - - @Test - public void outputStreamPrintlnChar() throws Exception { - char c = 1; - - this.response.getOutputStream().println(c); - - verify(this.out).println(c); - } - - @Test - public void outputStreamPrintlnInt() throws Exception { - int i = 1; - - this.response.getOutputStream().println(i); - - verify(this.out).println(i); - } - - @Test - public void outputStreamPrintlnLong() throws Exception { - long l = 1; - - this.response.getOutputStream().println(l); - - verify(this.out).println(l); - } - - @Test - public void outputStreamPrintlnFloat() throws Exception { - float f = 1; - - this.response.getOutputStream().println(f); - - verify(this.out).println(f); - } - - @Test - public void outputStreamPrintlnDouble() throws Exception { - double x = 1; - - this.response.getOutputStream().println(x); - - verify(this.out).println(x); - } - - @Test - public void outputStreamPrintlnString() throws Exception { - String x = "1"; - - this.response.getOutputStream().println(x); - - verify(this.out).println(x); - } - - // The amount of content specified in the setContentLength method of the response - // has been greater than zero and has been written to the response. - - @Test - public void contentLengthPrintWriterWriteIntCommits() throws Exception { - int expected = 1; - this.response.setContentLength(String.valueOf(expected).length()); - - this.response.getWriter().write(expected); - - assertThat(this.committed).isTrue(); - } - - @Test - public void contentLengthPrintWriterWriteIntMultiDigitCommits() throws Exception { - int expected = 10000; - this.response.setContentLength(String.valueOf(expected).length()); - - this.response.getWriter().write(expected); - - assertThat(this.committed).isTrue(); - } - - @Test - public void contentLengthPlus1PrintWriterWriteIntMultiDigitCommits() - throws Exception { - int expected = 10000; - this.response.setContentLength(String.valueOf(expected).length() + 1); - - this.response.getWriter().write(expected); - - assertThat(this.committed).isFalse(); - - this.response.getWriter().write(1); - - assertThat(this.committed).isTrue(); - } - - @Test - public void contentLengthPrintWriterWriteCharIntIntCommits() throws Exception { - char[] buff = new char[0]; - int off = 2; - int len = 3; - this.response.setContentLength(3); - - this.response.getWriter().write(buff, off, len); - - assertThat(this.committed).isTrue(); - } - - @Test - public void contentLengthPrintWriterWriteCharCommits() throws Exception { - char[] buff = new char[4]; - this.response.setContentLength(buff.length); - - this.response.getWriter().write(buff); - - assertThat(this.committed).isTrue(); - } - - @Test - public void contentLengthPrintWriterWriteStringIntIntCommits() throws Exception { - String s = ""; - int off = 2; - int len = 3; - this.response.setContentLength(3); - - this.response.getWriter().write(s, off, len); - - assertThat(this.committed).isTrue(); - } - - @Test - public void contentLengthPrintWriterWriteStringCommits() throws IOException { - String body = "something"; - this.response.setContentLength(body.length()); - - this.response.getWriter().write(body); - - assertThat(this.committed).isTrue(); - } - - @Test - public void printWriterWriteStringContentLengthCommits() throws IOException { - String body = "something"; - this.response.getWriter().write(body); - - this.response.setContentLength(body.length()); - - assertThat(this.committed).isTrue(); - } - - @Test - public void printWriterWriteStringDoesNotCommit() throws IOException { - String body = "something"; - - this.response.getWriter().write(body); - - assertThat(this.committed).isFalse(); - } - - @Test - public void contentLengthPrintWriterPrintBooleanCommits() throws Exception { - boolean b = true; - this.response.setContentLength(1); - - this.response.getWriter().print(b); - - assertThat(this.committed).isTrue(); - } - - @Test - public void contentLengthPrintWriterPrintCharCommits() throws Exception { - char c = 1; - this.response.setContentLength(1); - - this.response.getWriter().print(c); - - assertThat(this.committed).isTrue(); - } - - @Test - public void contentLengthPrintWriterPrintIntCommits() throws Exception { - int i = 1234; - this.response.setContentLength(String.valueOf(i).length()); - - this.response.getWriter().print(i); - - assertThat(this.committed).isTrue(); - } - - @Test - public void contentLengthPrintWriterPrintLongCommits() throws Exception { - long l = 12345; - this.response.setContentLength(String.valueOf(l).length()); - - this.response.getWriter().print(l); - - assertThat(this.committed).isTrue(); - } - - @Test - public void contentLengthPrintWriterPrintFloatCommits() throws Exception { - float f = 12345; - this.response.setContentLength(String.valueOf(f).length()); - - this.response.getWriter().print(f); - - assertThat(this.committed).isTrue(); - } - - @Test - public void contentLengthPrintWriterPrintDoubleCommits() throws Exception { - double x = 1.2345; - this.response.setContentLength(String.valueOf(x).length()); - - this.response.getWriter().print(x); - - assertThat(this.committed).isTrue(); - } - - @Test - public void contentLengthPrintWriterPrintCharArrayCommits() throws Exception { - char[] x = new char[10]; - this.response.setContentLength(x.length); - - this.response.getWriter().print(x); - - assertThat(this.committed).isTrue(); - } - - @Test - public void contentLengthPrintWriterPrintStringCommits() throws Exception { - String x = "12345"; - this.response.setContentLength(x.length()); - - this.response.getWriter().print(x); - - assertThat(this.committed).isTrue(); - } - - @Test - public void contentLengthPrintWriterPrintObjectCommits() throws Exception { - Object x = "12345"; - this.response.setContentLength(String.valueOf(x).length()); - - this.response.getWriter().print(x); - - assertThat(this.committed).isTrue(); - } - - @Test - public void contentLengthPrintWriterPrintlnCommits() throws Exception { - this.response.setContentLength(NL.length()); - - this.response.getWriter().println(); - - assertThat(this.committed).isTrue(); - } - - @Test - public void contentLengthPrintWriterPrintlnBooleanCommits() throws Exception { - boolean b = true; - this.response.setContentLength(1); - - this.response.getWriter().println(b); - - assertThat(this.committed).isTrue(); - } - - @Test - public void contentLengthPrintWriterPrintlnCharCommits() throws Exception { - char c = 1; - this.response.setContentLength(1); - - this.response.getWriter().println(c); - - assertThat(this.committed).isTrue(); - } - - @Test - public void contentLengthPrintWriterPrintlnIntCommits() throws Exception { - int i = 12345; - this.response.setContentLength(String.valueOf(i).length()); - - this.response.getWriter().println(i); - - assertThat(this.committed).isTrue(); - } - - @Test - public void contentLengthPrintWriterPrintlnLongCommits() throws Exception { - long l = 12345678; - this.response.setContentLength(String.valueOf(l).length()); - - this.response.getWriter().println(l); - - assertThat(this.committed).isTrue(); - } - - @Test - public void contentLengthPrintWriterPrintlnFloatCommits() throws Exception { - float f = 1234; - this.response.setContentLength(String.valueOf(f).length()); - - this.response.getWriter().println(f); - - assertThat(this.committed).isTrue(); - } - - @Test - public void contentLengthPrintWriterPrintlnDoubleCommits() throws Exception { - double x = 1; - this.response.setContentLength(String.valueOf(x).length()); - - this.response.getWriter().println(x); - - assertThat(this.committed).isTrue(); - } - - @Test - public void contentLengthPrintWriterPrintlnCharArrayCommits() throws Exception { - char[] x = new char[20]; - this.response.setContentLength(x.length); - - this.response.getWriter().println(x); - - assertThat(this.committed).isTrue(); - } - - @Test - public void contentLengthPrintWriterPrintlnStringCommits() throws Exception { - String x = "1"; - this.response.setContentLength(String.valueOf(x).length()); - - this.response.getWriter().println(x); - - assertThat(this.committed).isTrue(); - } - - @Test - public void contentLengthPrintWriterPrintlnObjectCommits() throws Exception { - Object x = "1"; - this.response.setContentLength(String.valueOf(x).length()); - - this.response.getWriter().println(x); - - assertThat(this.committed).isTrue(); - } - - @Test - public void contentLengthPrintWriterAppendCharSequenceCommits() throws Exception { - String x = "a"; - this.response.setContentLength(String.valueOf(x).length()); - - this.response.getWriter().append(x); - - assertThat(this.committed).isTrue(); - } - - @Test - public void contentLengthPrintWriterAppendCharSequenceIntIntCommits() - throws Exception { - String x = "abcdef"; - int start = 1; - int end = 3; - this.response.setContentLength(end - start); - - this.response.getWriter().append(x, start, end); - - assertThat(this.committed).isTrue(); - } - - @Test - public void contentLengthPrintWriterAppendCharCommits() throws Exception { - char x = 1; - this.response.setContentLength(1); - - this.response.getWriter().append(x); - - assertThat(this.committed).isTrue(); - } - - @Test - public void contentLengthOutputStreamWriteIntCommits() throws Exception { - int expected = 1; - this.response.setContentLength(String.valueOf(expected).length()); - - this.response.getOutputStream().write(expected); - - assertThat(this.committed).isTrue(); - } - - @Test - public void contentLengthOutputStreamWriteIntMultiDigitCommits() throws Exception { - int expected = 10000; - this.response.setContentLength(String.valueOf(expected).length()); - - this.response.getOutputStream().write(expected); - - assertThat(this.committed).isTrue(); - } - - @Test - public void contentLengthPlus1OutputStreamWriteIntMultiDigitCommits() - throws Exception { - int expected = 10000; - this.response.setContentLength(String.valueOf(expected).length() + 1); - - this.response.getOutputStream().write(expected); - - assertThat(this.committed).isFalse(); - - this.response.getOutputStream().write(1); - - assertThat(this.committed).isTrue(); - } - - // gh-171 - @Test - public void contentLengthPlus1OutputStreamWriteByteArrayMultiDigitCommits() - throws Exception { - String expected = "{\n" + " \"parameterName\" : \"_csrf\",\n" - + " \"token\" : \"06300b65-c4aa-4c8f-8cda-39ee17f545a0\",\n" - + " \"headerName\" : \"X-CSRF-TOKEN\"\n" + "}"; - this.response.setContentLength(expected.length() + 1); - - this.response.getOutputStream().write(expected.getBytes()); - - assertThat(this.committed).isFalse(); - - this.response.getOutputStream().write("1".getBytes("UTF-8")); - - assertThat(this.committed).isTrue(); - } - - @Test - public void contentLengthOutputStreamPrintBooleanCommits() throws Exception { - boolean b = true; - this.response.setContentLength(1); - - this.response.getOutputStream().print(b); - - assertThat(this.committed).isTrue(); - } - - @Test - public void contentLengthOutputStreamPrintCharCommits() throws Exception { - char c = 1; - this.response.setContentLength(1); - - this.response.getOutputStream().print(c); - - assertThat(this.committed).isTrue(); - } - - @Test - public void contentLengthOutputStreamPrintIntCommits() throws Exception { - int i = 1234; - this.response.setContentLength(String.valueOf(i).length()); - - this.response.getOutputStream().print(i); - - assertThat(this.committed).isTrue(); - } - - @Test - public void contentLengthOutputStreamPrintLongCommits() throws Exception { - long l = 12345; - this.response.setContentLength(String.valueOf(l).length()); - - this.response.getOutputStream().print(l); - - assertThat(this.committed).isTrue(); - } - - @Test - public void contentLengthOutputStreamPrintFloatCommits() throws Exception { - float f = 12345; - this.response.setContentLength(String.valueOf(f).length()); - - this.response.getOutputStream().print(f); - - assertThat(this.committed).isTrue(); - } - - @Test - public void contentLengthOutputStreamPrintDoubleCommits() throws Exception { - double x = 1.2345; - this.response.setContentLength(String.valueOf(x).length()); - - this.response.getOutputStream().print(x); - - assertThat(this.committed).isTrue(); - } - - @Test - public void contentLengthOutputStreamPrintStringCommits() throws Exception { - String x = "12345"; - this.response.setContentLength(x.length()); - - this.response.getOutputStream().print(x); - - assertThat(this.committed).isTrue(); - } - - @Test - public void contentLengthOutputStreamPrintlnCommits() throws Exception { - this.response.setContentLength(NL.length()); - - this.response.getOutputStream().println(); - - assertThat(this.committed).isTrue(); - } - - @Test - public void contentLengthOutputStreamPrintlnBooleanCommits() throws Exception { - boolean b = true; - this.response.setContentLength(1); - - this.response.getOutputStream().println(b); - - assertThat(this.committed).isTrue(); - } - - @Test - public void contentLengthOutputStreamPrintlnCharCommits() throws Exception { - char c = 1; - this.response.setContentLength(1); - - this.response.getOutputStream().println(c); - - assertThat(this.committed).isTrue(); - } - - @Test - public void contentLengthOutputStreamPrintlnIntCommits() throws Exception { - int i = 12345; - this.response.setContentLength(String.valueOf(i).length()); - - this.response.getOutputStream().println(i); - - assertThat(this.committed).isTrue(); - } - - @Test - public void contentLengthOutputStreamPrintlnLongCommits() throws Exception { - long l = 12345678; - this.response.setContentLength(String.valueOf(l).length()); - - this.response.getOutputStream().println(l); - - assertThat(this.committed).isTrue(); - } - - @Test - public void contentLengthOutputStreamPrintlnFloatCommits() throws Exception { - float f = 1234; - this.response.setContentLength(String.valueOf(f).length()); - - this.response.getOutputStream().println(f); - - assertThat(this.committed).isTrue(); - } - - @Test - public void contentLengthOutputStreamPrintlnDoubleCommits() throws Exception { - double x = 1; - this.response.setContentLength(String.valueOf(x).length()); - - this.response.getOutputStream().println(x); - - assertThat(this.committed).isTrue(); - } - - @Test - public void contentLengthOutputStreamPrintlnStringCommits() throws Exception { - String x = "1"; - this.response.setContentLength(String.valueOf(x).length()); - - this.response.getOutputStream().println(x); - - assertThat(this.committed).isTrue(); - } - - @Test - public void contentLengthDoesNotCommit() throws IOException { - String body = "something"; - - this.response.setContentLength(body.length()); - - assertThat(this.committed).isFalse(); - } - - @Test - public void contentLengthOutputStreamWriteStringCommits() throws IOException { - String body = "something"; - this.response.setContentLength(body.length()); - - this.response.getOutputStream().print(body); - - assertThat(this.committed).isTrue(); - } - - @Test - public void addHeaderContentLengthPrintWriterWriteStringCommits() throws Exception { - int expected = 1234; - this.response.addHeader("Content-Length", - String.valueOf(String.valueOf(expected).length())); - - this.response.getWriter().write(expected); - - assertThat(this.committed).isTrue(); - } - - @Test - public void bufferSizePrintWriterWriteCommits() throws Exception { - String expected = "1234567890"; - given(this.response.getBufferSize()).willReturn(expected.length()); - - this.response.getWriter().write(expected); - - assertThat(this.committed).isTrue(); - } - - @Test - public void bufferSizeCommitsOnce() throws Exception { - String expected = "1234567890"; - given(this.response.getBufferSize()).willReturn(expected.length()); - - this.response.getWriter().write(expected); - - assertThat(this.committed).isTrue(); - - this.committed = false; - - this.response.getWriter().write(expected); - - assertThat(this.committed).isFalse(); - } -} diff --git a/spring-session/src/test/java/org/springframework/session/web/http/OncePerRequestFilterTests.java b/spring-session/src/test/java/org/springframework/session/web/http/OncePerRequestFilterTests.java deleted file mode 100644 index 420a8f1..0000000 --- a/spring-session/src/test/java/org/springframework/session/web/http/OncePerRequestFilterTests.java +++ /dev/null @@ -1,98 +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.io.IOException; -import java.util.ArrayList; -import java.util.List; - -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.junit.Before; -import org.junit.Test; - -import org.springframework.mock.web.MockFilterChain; -import org.springframework.mock.web.MockHttpServletRequest; -import org.springframework.mock.web.MockHttpServletResponse; - -import static org.assertj.core.api.Assertions.assertThat; - -public class OncePerRequestFilterTests { - private MockHttpServletRequest request; - private MockHttpServletResponse response; - private MockFilterChain chain; - private OncePerRequestFilter filter; - private HttpServlet servlet; - - private List invocations; - - @Before - @SuppressWarnings("serial") - public void setup() { - this.servlet = new HttpServlet() { - }; - this.request = new MockHttpServletRequest(); - this.response = new MockHttpServletResponse(); - this.chain = new MockFilterChain(); - this.invocations = new ArrayList(); - this.filter = new OncePerRequestFilter() { - @Override - protected void doFilterInternal(HttpServletRequest request, - HttpServletResponse response, FilterChain filterChain) - throws ServletException, IOException { - OncePerRequestFilterTests.this.invocations.add(this); - filterChain.doFilter(request, response); - } - }; - } - - @Test - public void doFilterOnce() throws ServletException, IOException { - this.filter.doFilter(this.request, this.response, this.chain); - - assertThat(this.invocations).containsOnly(this.filter); - } - - @Test - public void doFilterMultiOnlyIvokesOnce() throws ServletException, IOException { - this.filter.doFilter(this.request, this.response, - new MockFilterChain(this.servlet, this.filter)); - - assertThat(this.invocations).containsOnly(this.filter); - } - - @Test - public void doFilterOtherSubclassInvoked() throws ServletException, IOException { - OncePerRequestFilter filter2 = new OncePerRequestFilter() { - @Override - protected void doFilterInternal(HttpServletRequest request, - HttpServletResponse response, FilterChain filterChain) - throws ServletException, IOException { - OncePerRequestFilterTests.this.invocations.add(this); - filterChain.doFilter(request, response); - } - }; - this.filter.doFilter(this.request, this.response, - new MockFilterChain(this.servlet, filter2)); - - assertThat(this.invocations).containsOnly(this.filter, filter2); - } -} diff --git a/spring-session/src/test/java/org/springframework/session/web/http/SessionEventHttpSessionListenerAdapterTests.java b/spring-session/src/test/java/org/springframework/session/web/http/SessionEventHttpSessionListenerAdapterTests.java deleted file mode 100644 index 099c6be..0000000 --- a/spring-session/src/test/java/org/springframework/session/web/http/SessionEventHttpSessionListenerAdapterTests.java +++ /dev/null @@ -1,118 +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.web.http; - -import java.util.Arrays; -import java.util.Collections; - -import javax.servlet.ServletContext; -import javax.servlet.http.HttpSessionEvent; -import javax.servlet.http.HttpSessionListener; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; - -import org.springframework.session.MapSession; -import org.springframework.session.Session; -import org.springframework.session.events.SessionCreatedEvent; -import org.springframework.session.events.SessionDestroyedEvent; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; - -/** - * @author Rob Winch - * @since 1.1 - */ -@RunWith(MockitoJUnitRunner.class) -public class SessionEventHttpSessionListenerAdapterTests { - @Mock - HttpSessionListener listener1; - @Mock - HttpSessionListener listener2; - @Mock - ServletContext servletContext; - @Captor - ArgumentCaptor sessionEvent; - - SessionDestroyedEvent destroyed; - SessionCreatedEvent created; - SessionEventHttpSessionListenerAdapter listener; - - @Before - public void setup() { - this.listener = new SessionEventHttpSessionListenerAdapter( - Arrays.asList(this.listener1, this.listener2)); - - Session session = new MapSession(); - this.destroyed = new SessionDestroyedEvent(this, session); - this.created = new SessionCreatedEvent(this, session); - } - - // We want relaxed constructor that will allow for an empty listeners to - // make configuration easier (i.e. autowire all HttpSessionListeners and might get - // none) - @Test - public void constructorEmptyWorks() { - new SessionEventHttpSessionListenerAdapter( - Collections.emptyList()); - } - - /** - * Make sure that we short circuit onApplicationEvent as early as possible if no - * listeners - */ - @Test - public void onApplicationEventEmptyListenersDoesNotUseEvent() { - this.listener = new SessionEventHttpSessionListenerAdapter( - Collections.emptyList()); - this.destroyed = mock(SessionDestroyedEvent.class); - - this.listener.onApplicationEvent(this.destroyed); - - verifyZeroInteractions(this.destroyed, this.listener1, this.listener2); - } - - @Test - public void onApplicationEventDestroyed() { - this.listener.onApplicationEvent(this.destroyed); - - verify(this.listener1).sessionDestroyed(this.sessionEvent.capture()); - verify(this.listener2).sessionDestroyed(this.sessionEvent.capture()); - - assertThat(this.sessionEvent.getValue().getSession().getId()) - .isEqualTo(this.destroyed.getSessionId()); - } - - @Test - public void onApplicationEventCreated() { - this.listener.onApplicationEvent(this.created); - - verify(this.listener1).sessionCreated(this.sessionEvent.capture()); - verify(this.listener2).sessionCreated(this.sessionEvent.capture()); - - assertThat(this.sessionEvent.getValue().getSession().getId()) - .isEqualTo(this.created.getSessionId()); - } -} diff --git a/spring-session/src/test/java/org/springframework/session/web/http/SessionRepositoryFilterTests.java b/spring-session/src/test/java/org/springframework/session/web/http/SessionRepositoryFilterTests.java deleted file mode 100644 index d020fe6..0000000 --- a/spring-session/src/test/java/org/springframework/session/web/http/SessionRepositoryFilterTests.java +++ /dev/null @@ -1,1486 +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.web.http; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Base64; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.NoSuchElementException; -import java.util.concurrent.TimeUnit; - -import javax.servlet.FilterChain; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; -import javax.servlet.http.HttpSessionContext; - -import org.assertj.core.data.Offset; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; - -import org.springframework.core.Ordered; -import org.springframework.core.annotation.AnnotationAwareOrderComparator; -import org.springframework.mock.web.MockFilterChain; -import org.springframework.mock.web.MockHttpServletRequest; -import org.springframework.mock.web.MockHttpServletResponse; -import org.springframework.mock.web.MockServletContext; -import org.springframework.session.ExpiringSession; -import org.springframework.session.MapSession; -import org.springframework.session.MapSessionRepository; -import org.springframework.session.Session; -import org.springframework.session.SessionRepository; -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.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; - -@RunWith(MockitoJUnitRunner.class) -@SuppressWarnings("deprecation") -public class SessionRepositoryFilterTests { - @Mock - private HttpSessionStrategy strategy; - - private Map sessions; - - private SessionRepository sessionRepository; - - private SessionRepositoryFilter filter; - - private MockHttpServletRequest request; - - private MockHttpServletResponse response; - - private MockFilterChain chain; - - @Before - public void setup() throws Exception { - this.sessions = new HashMap(); - this.sessionRepository = new MapSessionRepository(this.sessions); - this.filter = new SessionRepositoryFilter( - this.sessionRepository); - setupRequest(); - } - - @Test - public void doFilterCreateDate() throws Exception { - final String CREATE_ATTR = "create"; - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - long creationTime = wrappedRequest.getSession().getCreationTime(); - long now = System.currentTimeMillis(); - assertThat(now - creationTime).isGreaterThanOrEqualTo(0).isLessThan(5000); - SessionRepositoryFilterTests.this.request.setAttribute(CREATE_ATTR, - creationTime); - } - }); - - final long expectedCreationTime = (Long) this.request.getAttribute(CREATE_ATTR); - Thread.sleep(50L); - nextRequest(); - - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - long creationTime = wrappedRequest.getSession().getCreationTime(); - - assertThat(creationTime).isEqualTo(expectedCreationTime); - } - }); - } - - @Test - public void doFilterCreateSetsLastAccessedTime() throws Exception { - MapSession session = new MapSession(); - session.setLastAccessedTime(0L); - this.sessionRepository = spy(this.sessionRepository); - given(this.sessionRepository.createSession()).willReturn(session); - this.filter = new SessionRepositoryFilter( - this.sessionRepository); - - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - HttpSession session = wrappedRequest.getSession(); - long now = System.currentTimeMillis(); - long fiveSecondsAgo = now - TimeUnit.SECONDS.toMillis(5); - assertThat(session.getLastAccessedTime()).isLessThanOrEqualTo(now); - assertThat(session.getLastAccessedTime()) - .isGreaterThanOrEqualTo(fiveSecondsAgo); - } - }); - } - - @Test - public void doFilterLastAccessedTime() throws Exception { - final String ACCESS_ATTR = "create"; - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - long lastAccessed = wrappedRequest.getSession().getLastAccessedTime(); - assertThat(lastAccessed).isCloseTo( - wrappedRequest.getSession().getCreationTime(), Offset.offset(5L)); - SessionRepositoryFilterTests.this.request.setAttribute(ACCESS_ATTR, - lastAccessed); - } - }); - - Thread.sleep(50L); - nextRequest(); - - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - long lastAccessed = wrappedRequest.getSession().getLastAccessedTime(); - - assertThat(lastAccessed) - .isGreaterThan(wrappedRequest.getSession().getCreationTime()); - } - }); - } - - @Test - public void doFilterId() throws Exception { - final String ID_ATTR = "create"; - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - String id = wrappedRequest.getSession().getId(); - assertThat(id).isNotNull(); - assertThat(wrappedRequest.getSession().getId()).isEqualTo(id); - SessionRepositoryFilterTests.this.request.setAttribute(ID_ATTR, id); - } - }); - - final String id = (String) this.request.getAttribute(ID_ATTR); - assertThat(base64Decode(getSessionCookie().getValue())).isEqualTo(id); - setSessionCookie(id); - - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - assertThat(wrappedRequest.getSession().getId()).isEqualTo(id); - } - }); - } - - @Test - public void doFilterIdChanges() throws Exception { - final String ID_ATTR = "create"; - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - String id = wrappedRequest.getSession().getId(); - SessionRepositoryFilterTests.this.request.setAttribute(ID_ATTR, id); - } - }); - - final String id = (String) this.request.getAttribute(ID_ATTR); - setupRequest(); - - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - assertThat(wrappedRequest.getSession().getId()).isNotEqualTo(id); - } - }); - } - - @Test - public void doFilterServletContext() throws Exception { - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - ServletContext context = wrappedRequest.getSession().getServletContext(); - assertThat(context).isSameAs(wrappedRequest.getServletContext()); - } - }); - } - - // gh-111 - @Test - public void doFilterServletContextExplicit() throws Exception { - final ServletContext expectedContext = new MockServletContext(); - this.filter = new SessionRepositoryFilter( - this.sessionRepository); - this.filter.setServletContext(expectedContext); - - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - ServletContext context = wrappedRequest.getSession().getServletContext(); - assertThat(context).isSameAs(expectedContext); - } - }); - } - - @Test - public void doFilterMaxInactiveIntervalDefault() throws Exception { - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - int interval = wrappedRequest.getSession().getMaxInactiveInterval(); - // 30 minute default (same as - // Tomcat) - assertThat(interval).isEqualTo(1800); - } - }); - } - - @Test - public void doFilterMaxInactiveIntervalOverride() throws Exception { - final int interval = 600; - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - wrappedRequest.getSession().setMaxInactiveInterval(interval); - assertThat(wrappedRequest.getSession().getMaxInactiveInterval()) - .isEqualTo(interval); - } - }); - - nextRequest(); - - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - assertThat(wrappedRequest.getSession().getMaxInactiveInterval()) - .isEqualTo(interval); - } - }); - } - - @Test - public void doFilterAttribute() throws Exception { - final String ATTR = "ATTR"; - final String VALUE = "VALUE"; - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - wrappedRequest.getSession().setAttribute(ATTR, VALUE); - assertThat(wrappedRequest.getSession().getAttribute(ATTR)) - .isEqualTo(VALUE); - assertThat( - Collections.list(wrappedRequest.getSession().getAttributeNames())) - .containsOnly(ATTR); - } - }); - - nextRequest(); - - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - assertThat(wrappedRequest.getSession().getAttribute(ATTR)) - .isEqualTo(VALUE); - assertThat( - Collections.list(wrappedRequest.getSession().getAttributeNames())) - .containsOnly(ATTR); - } - }); - - nextRequest(); - - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - assertThat(wrappedRequest.getSession().getAttribute(ATTR)) - .isEqualTo(VALUE); - - wrappedRequest.getSession().removeAttribute(ATTR); - - assertThat(wrappedRequest.getSession().getAttribute(ATTR)).isNull(); - } - }); - - nextRequest(); - - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - assertThat(wrappedRequest.getSession().getAttribute(ATTR)).isNull(); - } - }); - } - - @Test - public void doFilterValue() throws Exception { - final String ATTR = "ATTR"; - final String VALUE = "VALUE"; - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - wrappedRequest.getSession().putValue(ATTR, VALUE); - assertThat(wrappedRequest.getSession().getValue(ATTR)).isEqualTo(VALUE); - assertThat(Arrays.asList(wrappedRequest.getSession().getValueNames())) - .containsOnly(ATTR); - } - }); - - nextRequest(); - - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - assertThat(wrappedRequest.getSession().getValue(ATTR)).isEqualTo(VALUE); - assertThat(Arrays.asList(wrappedRequest.getSession().getValueNames())) - .containsOnly(ATTR); - } - }); - - nextRequest(); - - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - assertThat(wrappedRequest.getSession().getValue(ATTR)).isEqualTo(VALUE); - - wrappedRequest.getSession().removeValue(ATTR); - - assertThat(wrappedRequest.getSession().getValue(ATTR)).isNull(); - } - }); - - nextRequest(); - - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - assertThat(wrappedRequest.getSession().getValue(ATTR)).isNull(); - } - }); - } - - @Test - public void doFilterIsNewTrue() throws Exception { - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - assertThat(wrappedRequest.getSession().isNew()).isTrue(); - assertThat(wrappedRequest.getSession().isNew()).isTrue(); - } - }); - } - - @Test - public void doFilterIsNewFalse() throws Exception { - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - wrappedRequest.getSession(); - } - }); - - nextRequest(); - this.response.reset(); - - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - assertThat(wrappedRequest.getSession().isNew()).isFalse(); - } - }); - - assertThat(this.response.getCookie("SESSION")).isNull(); - } - - @Test - public void doFilterSetsCookieIfChanged() throws Exception { - this.sessionRepository = new MapSessionRepository() { - @Override - public ExpiringSession getSession(String id) { - return createSession(); - } - }; - this.filter = new SessionRepositoryFilter( - this.sessionRepository); - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - wrappedRequest.getSession(); - } - }); - assertThat(this.response.getCookie("SESSION")).isNotNull(); - - nextRequest(); - - this.response.reset(); - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - assertThat(wrappedRequest.getSession().isNew()).isFalse(); - } - }); - - assertThat(this.response.getCookie("SESSION")).isNotNull(); - } - - @Test - public void doFilterGetSessionNew() throws Exception { - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - wrappedRequest.getSession(); - } - }); - - assertNewSession(); - } - - @Test - public void doFilterGetSessionTrueNew() throws Exception { - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - wrappedRequest.getSession(true); - } - }); - - assertNewSession(); - } - - @Test - public void doFilterGetSessionFalseNew() throws Exception { - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - wrappedRequest.getSession(false); - } - }); - - assertNoSession(); - } - - @Test - public void doFilterIsRequestedValidSessionTrue() throws Exception { - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - wrappedRequest.getSession(); - } - }); - - nextRequest(); - this.request.setRequestedSessionIdValid(false); - - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - assertThat(wrappedRequest.isRequestedSessionIdValid()).isTrue(); - } - }); - } - - // gh-152 - @Test - public void doFilterChangeSessionId() throws Exception { - final String ATTR = "ATTRIBUTE"; - final String VALUE = "VALUE"; - - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - wrappedRequest.getSession().setAttribute(ATTR, VALUE); - } - }); - - final String originalSessionId = base64Decode(getSessionCookie().getValue()); - nextRequest(); - - // change the session id - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - HttpSession originalSession = wrappedRequest.getSession(); - assertThat(originalSession.getId()).isEqualTo(originalSessionId); - - String changeSessionId = ReflectionTestUtils.invokeMethod(wrappedRequest, - "changeSessionId"); - assertThat(changeSessionId).isNotEqualTo(originalSessionId); - // gh-227 - assertThat(originalSession.getId()).isEqualTo(changeSessionId); - } - }); - - // the old session was removed - final String changedSessionId = getSessionCookie().getValue(); - assertThat(originalSessionId).isNotEqualTo(changedSessionId); - assertThat(this.sessionRepository.getSession(originalSessionId)).isNull(); - - nextRequest(); - - // The attributes from previous session were migrated - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - assertThat(wrappedRequest.getSession().getAttribute(ATTR)) - .isEqualTo(VALUE); - } - }); - } - - @Test - public void doFilterChangeSessionIdNoSession() throws Exception { - // change the session id - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - try { - ReflectionTestUtils.invokeMethod(wrappedRequest, "changeSessionId"); - fail("Exected Exception"); - } - catch (IllegalStateException success) { - } - } - }); - } - - // gh-142, gh-153 - @Test - public void doFilterIsRequestedValidSessionFalseInvalidId() throws Exception { - setSessionCookie("invalid"); - this.request.setRequestedSessionIdValid(true); - - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - assertThat(wrappedRequest.isRequestedSessionIdValid()).isFalse(); - } - }); - } - - @Test - public void doFilterIsRequestedValidSessionFalse() throws Exception { - this.request.setRequestedSessionIdValid(true); - - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - assertThat(wrappedRequest.isRequestedSessionIdValid()).isFalse(); - } - }); - } - - @Test - public void doFilterGetSessionGetSessionFalse() throws Exception { - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - wrappedRequest.getSession(); - } - }); - - nextRequest(); - - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - assertThat(wrappedRequest.getSession(false)).isNotNull(); - } - }); - } - - // gh-229 - @Test - public void doFilterGetSessionGetSessionOnError() throws Exception { - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - wrappedRequest.getSession().setAttribute("a", "b"); - } - }); - - // reuse the same request similar to processing an ERROR dispatch - - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - assertThat(wrappedRequest.getSession(false)).isNotNull(); - } - }); - - assertThat(this.sessions.size()).isEqualTo(1); - } - - @Test - public void doFilterCookieSecuritySettings() throws Exception { - this.request.setSecure(true); - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - wrappedRequest.getSession(); - } - }); - - Cookie session = getSessionCookie(); - assertThat(session.isHttpOnly()).describedAs("Session Cookie should be HttpOnly") - .isTrue(); - assertThat(session.getSecure()) - .describedAs("Session Cookie should be marked as Secure").isTrue(); - } - - @Test - public void doFilterSessionContext() throws Exception { - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - HttpSessionContext sessionContext = wrappedRequest.getSession() - .getSessionContext(); - assertThat(sessionContext).isNotNull(); - assertThat(sessionContext.getSession("a")).isNull(); - assertThat(sessionContext.getIds()).isNotNull(); - assertThat(sessionContext.getIds().hasMoreElements()).isFalse(); - - try { - sessionContext.getIds().nextElement(); - fail("Expected Exception"); - } - catch (NoSuchElementException success) { - } - } - }); - } - - // --- saving - - @Test - public void doFilterGetAttr() throws Exception { - final String ATTR_NAME = "attr"; - final String ATTR_VALUE = "value"; - final String ATTR_NAME2 = "attr2"; - final String ATTR_VALUE2 = "value2"; - - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - wrappedRequest.getSession().setAttribute(ATTR_NAME, ATTR_VALUE); - wrappedRequest.getSession().setAttribute(ATTR_NAME2, ATTR_VALUE2); - } - }); - - assertNewSession(); - - nextRequest(); - - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - assertThat(wrappedRequest.getSession().getAttribute(ATTR_NAME)) - .isEqualTo(ATTR_VALUE); - assertThat(wrappedRequest.getSession().getAttribute(ATTR_NAME2)) - .isEqualTo(ATTR_VALUE2); - } - }); - } - - // --- invalidate - - @Test - public void doFilterInvalidateInvalidateIllegalState() throws Exception { - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - HttpSession session = wrappedRequest.getSession(); - session.invalidate(); - try { - session.invalidate(); - fail("Expected Exception"); - } - catch (IllegalStateException success) { - } - } - }); - } - - @Test - public void doFilterInvalidateCreationTimeIllegalState() throws Exception { - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - HttpSession session = wrappedRequest.getSession(); - session.invalidate(); - try { - session.getCreationTime(); - fail("Expected Exception"); - } - catch (IllegalStateException success) { - } - } - }); - } - - @Test - public void doFilterInvalidateAttributeIllegalState() throws Exception { - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - HttpSession session = wrappedRequest.getSession(); - session.invalidate(); - try { - session.getAttribute("attr"); - fail("Expected Exception"); - } - catch (IllegalStateException success) { - } - } - }); - } - - @Test - public void doFilterInvalidateValueIllegalState() throws Exception { - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - HttpSession session = wrappedRequest.getSession(); - session.invalidate(); - try { - session.getValue("attr"); - fail("Expected Exception"); - } - catch (IllegalStateException success) { - } - } - }); - } - - @Test - public void doFilterInvalidateAttributeNamesIllegalState() throws Exception { - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - HttpSession session = wrappedRequest.getSession(); - session.invalidate(); - try { - session.getAttributeNames(); - fail("Expected Exception"); - } - catch (IllegalStateException success) { - } - } - }); - } - - @Test - public void doFilterInvalidateValueNamesIllegalState() throws Exception { - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - HttpSession session = wrappedRequest.getSession(); - session.invalidate(); - try { - session.getValueNames(); - fail("Expected Exception"); - } - catch (IllegalStateException success) { - } - } - }); - } - - @Test - public void doFilterInvalidateSetAttributeIllegalState() throws Exception { - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - HttpSession session = wrappedRequest.getSession(); - session.invalidate(); - try { - session.setAttribute("a", "b"); - fail("Expected Exception"); - } - catch (IllegalStateException success) { - } - } - }); - } - - @Test - public void doFilterInvalidatePutValueIllegalState() throws Exception { - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - HttpSession session = wrappedRequest.getSession(); - session.invalidate(); - try { - session.putValue("a", "b"); - fail("Expected Exception"); - } - catch (IllegalStateException success) { - } - } - }); - } - - @Test - public void doFilterInvalidateRemoveAttributeIllegalState() throws Exception { - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - HttpSession session = wrappedRequest.getSession(); - session.invalidate(); - try { - session.removeAttribute("name"); - fail("Expected Exception"); - } - catch (IllegalStateException success) { - } - } - }); - } - - @Test - public void doFilterInvalidateRemoveValueIllegalState() throws Exception { - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - HttpSession session = wrappedRequest.getSession(); - session.invalidate(); - try { - session.removeValue("name"); - fail("Expected Exception"); - } - catch (IllegalStateException success) { - } - } - }); - } - - @Test - public void doFilterInvalidateNewIllegalState() throws Exception { - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - HttpSession session = wrappedRequest.getSession(); - session.invalidate(); - try { - session.isNew(); - fail("Expected Exception"); - } - catch (IllegalStateException success) { - } - } - }); - } - - @Test - public void doFilterInvalidateLastAccessedTimeIllegalState() throws Exception { - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - HttpSession session = wrappedRequest.getSession(); - session.invalidate(); - try { - session.getLastAccessedTime(); - fail("Expected Exception"); - } - catch (IllegalStateException success) { - } - } - }); - } - - @Test - public void doFilterInvalidateId() throws Exception { - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - HttpSession session = wrappedRequest.getSession(); - session.invalidate(); - // no exception - session.getId(); - } - }); - } - - @Test - public void doFilterInvalidateServletContext() throws Exception { - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - HttpSession session = wrappedRequest.getSession(); - session.invalidate(); - - // no exception - session.getServletContext(); - } - }); - } - - @Test - public void doFilterInvalidateSessionContext() throws Exception { - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - HttpSession session = wrappedRequest.getSession(); - session.invalidate(); - - // no exception - session.getSessionContext(); - } - }); - } - - @Test - public void doFilterInvalidateMaxInteractiveInterval() throws Exception { - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - HttpSession session = wrappedRequest.getSession(); - session.invalidate(); - - // no exception - session.getMaxInactiveInterval(); - session.setMaxInactiveInterval(3600); - } - }); - } - - @Test - public void doFilterInvalidateAndGetSession() throws Exception { - final String ATTR_NAME = "attr"; - final String ATTR_VALUE = "value"; - final String ATTR_NAME2 = "attr2"; - final String ATTR_VALUE2 = "value2"; - - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - wrappedRequest.getSession().setAttribute(ATTR_NAME, ATTR_VALUE); - wrappedRequest.getSession().invalidate(); - wrappedRequest.getSession().setAttribute(ATTR_NAME2, ATTR_VALUE2); - } - }); - - assertNewSession(); - - nextRequest(); - - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - assertThat(wrappedRequest.getSession().getAttribute(ATTR_NAME)).isNull(); - assertThat(wrappedRequest.getSession().getAttribute(ATTR_NAME2)) - .isEqualTo(ATTR_VALUE2); - } - }); - } - - // --- invalid session ids - - @Test - public void doFilterGetSessionInvalidSessionId() throws Exception { - setSessionCookie("INVALID"); - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - wrappedRequest.getSession(); - } - }); - - assertNewSession(); - } - - @Test - public void doFilterGetSessionTrueInvalidSessionId() throws Exception { - setSessionCookie("INVALID"); - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - wrappedRequest.getSession(true); - } - }); - - assertNewSession(); - } - - @Test - public void doFilterGetSessionFalseInvalidSessionId() throws Exception { - setSessionCookie("INVALID"); - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest) { - wrappedRequest.getSession(false); - } - }); - - assertNoSession(); - } - - // --- commit response saves immediately - - @Test - public void doFilterSendError() throws Exception { - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest, - HttpServletResponse wrappedResponse) throws IOException { - String id = wrappedRequest.getSession().getId(); - wrappedResponse.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); - assertThat(SessionRepositoryFilterTests.this.sessionRepository - .getSession(id)).isNotNull(); - } - }); - } - - @Test - public void doFilterSendErrorAndMessage() throws Exception { - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest, - HttpServletResponse wrappedResponse) throws IOException { - String id = wrappedRequest.getSession().getId(); - wrappedResponse.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, - "Error"); - assertThat(SessionRepositoryFilterTests.this.sessionRepository - .getSession(id)).isNotNull(); - } - }); - } - - @Test - public void doFilterSendRedirect() throws Exception { - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest, - HttpServletResponse wrappedResponse) throws IOException { - String id = wrappedRequest.getSession().getId(); - wrappedResponse.sendRedirect("/"); - assertThat(SessionRepositoryFilterTests.this.sessionRepository - .getSession(id)).isNotNull(); - } - }); - } - - @Test - public void doFilterFlushBuffer() throws Exception { - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest, - HttpServletResponse wrappedResponse) throws IOException { - String id = wrappedRequest.getSession().getId(); - wrappedResponse.flushBuffer(); - assertThat(SessionRepositoryFilterTests.this.sessionRepository - .getSession(id)).isNotNull(); - } - }); - } - - @Test - public void doFilterOutputFlush() throws Exception { - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest, - HttpServletResponse wrappedResponse) throws IOException { - String id = wrappedRequest.getSession().getId(); - wrappedResponse.getOutputStream().flush(); - assertThat(SessionRepositoryFilterTests.this.sessionRepository - .getSession(id)).isNotNull(); - } - }); - } - - @Test - public void doFilterOutputClose() throws Exception { - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest, - HttpServletResponse wrappedResponse) throws IOException { - String id = wrappedRequest.getSession().getId(); - wrappedResponse.getOutputStream().close(); - assertThat(SessionRepositoryFilterTests.this.sessionRepository - .getSession(id)).isNotNull(); - } - }); - } - - @Test - public void doFilterWriterFlush() throws Exception { - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest, - HttpServletResponse wrappedResponse) throws IOException { - String id = wrappedRequest.getSession().getId(); - wrappedResponse.getWriter().flush(); - assertThat(SessionRepositoryFilterTests.this.sessionRepository - .getSession(id)).isNotNull(); - } - }); - } - - @Test - public void doFilterWriterClose() throws Exception { - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest, - HttpServletResponse wrappedResponse) throws IOException { - String id = wrappedRequest.getSession().getId(); - wrappedResponse.getWriter().close(); - assertThat(SessionRepositoryFilterTests.this.sessionRepository - .getSession(id)).isNotNull(); - } - }); - } - - // --- MultiHttpSessionStrategyAdapter - - @Test - public void doFilterAdapterGetRequestedSessionId() throws Exception { - this.filter.setHttpSessionStrategy(this.strategy); - final String expectedId = "MultiHttpSessionStrategyAdapter-requested-id"; - given(this.strategy.getRequestedSessionId(any(HttpServletRequest.class))) - .willReturn(expectedId); - - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest, - HttpServletResponse wrappedResponse) throws IOException { - String actualId = wrappedRequest.getRequestedSessionId(); - assertThat(actualId).isEqualTo(expectedId); - } - }); - } - - @Test - public void doFilterAdapterOnNewSession() throws Exception { - this.filter.setHttpSessionStrategy(this.strategy); - - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest, - HttpServletResponse wrappedResponse) throws IOException { - wrappedRequest.getSession(); - } - }); - - HttpServletRequest request = (HttpServletRequest) this.chain.getRequest(); - Session session = this.sessionRepository.getSession(request.getSession().getId()); - verify(this.strategy).onNewSession(eq(session), any(HttpServletRequest.class), - any(HttpServletResponse.class)); - } - - @Test - public void doFilterAdapterOnInvalidate() throws Exception { - this.filter.setHttpSessionStrategy(this.strategy); - - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest, - HttpServletResponse wrappedResponse) throws IOException { - wrappedRequest.getSession().getId(); - } - }); - - HttpServletRequest request = (HttpServletRequest) this.chain.getRequest(); - String id = request.getSession().getId(); - given(this.strategy.getRequestedSessionId(any(HttpServletRequest.class))) - .willReturn(id); - setupRequest(); - - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest, - HttpServletResponse wrappedResponse) throws IOException { - wrappedRequest.getSession().invalidate(); - } - }); - - verify(this.strategy).onInvalidateSession(any(HttpServletRequest.class), - any(HttpServletResponse.class)); - } - - // gh-188 - @Test - public void doFilterRequestSessionNoRequestSessionDoesNotInvalidate() - throws Exception { - this.filter.setHttpSessionStrategy(this.strategy); - - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest, - HttpServletResponse wrappedResponse) throws IOException { - wrappedRequest.getSession().getId(); - } - }); - - HttpServletRequest request = (HttpServletRequest) this.chain.getRequest(); - String id = request.getSession().getId(); - given(this.strategy.getRequestedSessionId(any(HttpServletRequest.class))) - .willReturn(id); - - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest, - HttpServletResponse wrappedResponse) throws IOException { - } - }); - - verify(this.strategy, never()).onInvalidateSession(any(HttpServletRequest.class), - any(HttpServletResponse.class)); - } - - @Test - @SuppressWarnings("unchecked") - public void doFilterRequestSessionNoRequestSessionNoSessionRepositoryInteractions() - throws Exception { - SessionRepository sessionRepository = spy( - new MapSessionRepository()); - - this.filter = new SessionRepositoryFilter(sessionRepository); - - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest, - HttpServletResponse wrappedResponse) throws IOException { - wrappedRequest.getSession().getId(); - } - }); - - reset(sessionRepository); - setupRequest(); - - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest, - HttpServletResponse wrappedResponse) throws IOException { - } - }); - - verifyZeroInteractions(sessionRepository); - } - - @Test - public void doFilterLazySessionCreation() throws Exception { - SessionRepository sessionRepository = spy( - new MapSessionRepository()); - - this.filter = new SessionRepositoryFilter(sessionRepository); - - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest, - HttpServletResponse wrappedResponse) throws IOException { - } - }); - - verifyZeroInteractions(sessionRepository); - } - - @Test - public void doFilterLazySessionUpdates() throws Exception { - ExpiringSession session = this.sessionRepository.createSession(); - this.sessionRepository.save(session); - SessionRepository sessionRepository = spy( - this.sessionRepository); - setSessionCookie(session.getId()); - - this.filter = new SessionRepositoryFilter(sessionRepository); - - doFilter(new DoInFilter() { - @Override - public void doFilter(HttpServletRequest wrappedRequest, - HttpServletResponse wrappedResponse) throws IOException { - } - }); - - verifyZeroInteractions(sessionRepository); - } - - // --- order - - @Test - public void order() { - assertThat(AnnotationAwareOrderComparator.INSTANCE.compare(this.filter, - new SessionRepositoryFilterDefaultOrder())); - } - - // We want the filter to work without any dependencies on Spring - @Test(expected = ClassCastException.class) - @SuppressWarnings("unused") - public void doesNotImplementOrdered() { - Ordered o = (Ordered) this.filter; - } - - @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)) - .getSession(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)) - .getSession(nonExistantSessionId); // still only called once - assertThat(session).isNull(); - assertThat(SessionRepositoryFilterTests.this.request - .getAttribute(SessionRepositoryFilter.INVALID_SESSION_ID_ATTR)) - .isNotNull(); - } - }); - } - - // --- helper methods - - private void assertNewSession() { - Cookie cookie = getSessionCookie(); - assertThat(cookie).isNotNull(); - assertThat(cookie.getMaxAge()).isEqualTo(-1); - assertThat(cookie.getValue()).isNotEqualTo("INVALID"); - assertThat(cookie.isHttpOnly()).describedAs("Cookie is expected to be HTTP Only") - .isTrue(); - assertThat(cookie.getSecure()) - .describedAs( - "Cookie secured is expected to be " + this.request.isSecure()) - .isEqualTo(this.request.isSecure()); - assertThat(this.request.getSession(false)) - .describedAs("The original HttpServletRequest HttpSession should be null") - .isNull(); - } - - private void assertNoSession() { - Cookie cookie = getSessionCookie(); - assertThat(cookie).isNull(); - assertThat(this.request.getSession(false)) - .describedAs("The original HttpServletRequest HttpSession should be null") - .isNull(); - } - - private Cookie getSessionCookie() { - return this.response.getCookie("SESSION"); - } - - private void setSessionCookie(String sessionId) { - this.request.setCookies(new Cookie("SESSION", base64Encode(sessionId))); - } - - private void setupRequest() { - this.request = new MockHttpServletRequest(); - this.response = new MockHttpServletResponse(); - this.chain = new MockFilterChain(); - } - - private void nextRequest() throws Exception { - Map nameToCookie = new HashMap(); - if (this.request.getCookies() != null) { - for (Cookie cookie : this.request.getCookies()) { - nameToCookie.put(cookie.getName(), cookie); - } - } - if (this.response.getCookies() != null) { - for (Cookie cookie : this.response.getCookies()) { - nameToCookie.put(cookie.getName(), cookie); - } - } - Cookie[] nextRequestCookies = new ArrayList(nameToCookie.values()) - .toArray(new Cookie[0]); - - setupRequest(); - - this.request.setCookies(nextRequestCookies); - } - - @SuppressWarnings("serial") - private void doFilter(final DoInFilter doInFilter) - throws ServletException, IOException { - this.chain = new MockFilterChain(new HttpServlet() { - }, new OncePerRequestFilter() { - @Override - protected void doFilterInternal(HttpServletRequest request, - HttpServletResponse response, FilterChain filterChain) - throws ServletException, IOException { - doInFilter.doFilter(request, response); - } - }); - this.filter.doFilter(this.request, this.response, this.chain); - } - - private static String base64Encode(String value) { - return Base64.getEncoder().encodeToString(value.getBytes()); - } - - private static String base64Decode(String value) { - return new String(Base64.getDecoder().decode(value)); - } - - abstract class DoInFilter { - void doFilter(HttpServletRequest wrappedRequest, - HttpServletResponse wrappedResponse) - throws ServletException, IOException { - doFilter(wrappedRequest); - } - - void doFilter(HttpServletRequest wrappedRequest) { - } - } - - static class SessionRepositoryFilterDefaultOrder implements Ordered { - public int getOrder() { - return SessionRepositoryFilter.DEFAULT_ORDER; - } - } -} diff --git a/spring-session/src/test/java/org/springframework/session/web/socket/handler/WebSocketConnectHandlerDecoratorFactoryTests.java b/spring-session/src/test/java/org/springframework/session/web/socket/handler/WebSocketConnectHandlerDecoratorFactoryTests.java deleted file mode 100644 index daed99d..0000000 --- a/spring-session/src/test/java/org/springframework/session/web/socket/handler/WebSocketConnectHandlerDecoratorFactoryTests.java +++ /dev/null @@ -1,81 +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.web.socket.handler; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; - -import org.springframework.context.ApplicationEvent; -import org.springframework.context.ApplicationEventPublisher; -import org.springframework.session.web.socket.events.SessionConnectEvent; -import org.springframework.web.socket.WebSocketHandler; -import org.springframework.web.socket.WebSocketSession; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.BDDMockito.willThrow; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.verify; - -@RunWith(MockitoJUnitRunner.class) -public class WebSocketConnectHandlerDecoratorFactoryTests { - @Mock - ApplicationEventPublisher eventPublisher; - @Mock - WebSocketHandler delegate; - @Mock - WebSocketSession session; - @Captor - ArgumentCaptor event; - - WebSocketConnectHandlerDecoratorFactory factory; - - @Before - public void setup() { - this.factory = new WebSocketConnectHandlerDecoratorFactory(this.eventPublisher); - } - - @Test(expected = IllegalArgumentException.class) - public void constructorNullEventPublisher() { - new WebSocketConnectHandlerDecoratorFactory(null); - } - - @Test - public void decorateAfterConnectionEstablished() throws Exception { - WebSocketHandler decorated = this.factory.decorate(this.delegate); - - decorated.afterConnectionEstablished(this.session); - - verify(this.eventPublisher).publishEvent(this.event.capture()); - assertThat(this.event.getValue().getWebSocketSession()).isSameAs(this.session); - } - - @Test - public void decorateAfterConnectionEstablishedEventError() throws Exception { - WebSocketHandler decorated = this.factory.decorate(this.delegate); - willThrow(new IllegalStateException("Test throw on publishEvent")) - .given(this.eventPublisher).publishEvent(any(ApplicationEvent.class)); - - decorated.afterConnectionEstablished(this.session); - - verify(this.eventPublisher).publishEvent(any(SessionConnectEvent.class)); - } -} diff --git a/spring-session/src/test/java/org/springframework/session/web/socket/handler/WebSocketRegistryListenerTests.java b/spring-session/src/test/java/org/springframework/session/web/socket/handler/WebSocketRegistryListenerTests.java deleted file mode 100644 index e89914a..0000000 --- a/spring-session/src/test/java/org/springframework/session/web/socket/handler/WebSocketRegistryListenerTests.java +++ /dev/null @@ -1,173 +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.web.socket.handler; - -import java.security.Principal; -import java.util.HashMap; -import java.util.Map; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; - -import org.springframework.messaging.Message; -import org.springframework.messaging.MessageHeaders; -import org.springframework.messaging.simp.SimpMessageHeaderAccessor; -import org.springframework.session.events.SessionDeletedEvent; -import org.springframework.session.events.SessionExpiredEvent; -import org.springframework.session.web.socket.events.SessionConnectEvent; -import org.springframework.session.web.socket.server.SessionRepositoryMessageInterceptor; -import org.springframework.test.util.ReflectionTestUtils; -import org.springframework.web.socket.CloseStatus; -import org.springframework.web.socket.WebSocketSession; -import org.springframework.web.socket.messaging.SessionDisconnectEvent; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -@RunWith(MockitoJUnitRunner.class) -public class WebSocketRegistryListenerTests { - @Mock - WebSocketSession wsSession; - @Mock - WebSocketSession wsSession2; - @Mock - Message message; - @Mock - Principal principal; - - SessionConnectEvent connect; - - SessionConnectEvent connect2; - - SessionDisconnectEvent disconnect; - - SessionDeletedEvent deleted; - - SessionExpiredEvent expired; - - Map attributes; - - String sessionId; - - WebSocketRegistryListener listener; - - @Before - public void setup() { - this.sessionId = "session-id"; - this.attributes = new HashMap(); - SessionRepositoryMessageInterceptor.setSessionId(this.attributes, this.sessionId); - - given(this.wsSession.getAttributes()).willReturn(this.attributes); - given(this.wsSession.getPrincipal()).willReturn(this.principal); - given(this.wsSession.getId()).willReturn("wsSession-id"); - - given(this.wsSession2.getAttributes()).willReturn(this.attributes); - given(this.wsSession2.getPrincipal()).willReturn(this.principal); - given(this.wsSession2.getId()).willReturn("wsSession-id2"); - - Map headers = new HashMap(); - headers.put(SimpMessageHeaderAccessor.SESSION_ATTRIBUTES, this.attributes); - given(this.message.getHeaders()).willReturn(new MessageHeaders(headers)); - - this.listener = new WebSocketRegistryListener(); - this.connect = new SessionConnectEvent(this.listener, this.wsSession); - this.connect2 = new SessionConnectEvent(this.listener, this.wsSession2); - this.disconnect = new SessionDisconnectEvent(this.listener, this.message, - this.wsSession.getId(), CloseStatus.NORMAL); - this.deleted = new SessionDeletedEvent(this.listener, this.sessionId); - this.expired = new SessionExpiredEvent(this.listener, this.sessionId); - } - - @Test - public void onApplicationEventConnectSessionDeleted() throws Exception { - this.listener.onApplicationEvent(this.connect); - - this.listener.onApplicationEvent(this.deleted); - - verify(this.wsSession).close(WebSocketRegistryListener.SESSION_EXPIRED_STATUS); - } - - @Test - public void onApplicationEventConnectSessionExpired() throws Exception { - this.listener.onApplicationEvent(this.connect); - - this.listener.onApplicationEvent(this.expired); - - verify(this.wsSession).close(WebSocketRegistryListener.SESSION_EXPIRED_STATUS); - } - - @Test - public void onApplicationEventConnectSessionDeletedNullPrincipal() throws Exception { - given(this.wsSession.getPrincipal()).willReturn(null); - this.listener.onApplicationEvent(this.connect); - - this.listener.onApplicationEvent(this.deleted); - - verify(this.wsSession, times(0)).close(any(CloseStatus.class)); - } - - @Test - public void onApplicationEventConnectDisconnect() throws Exception { - this.listener.onApplicationEvent(this.connect); - this.listener.onApplicationEvent(this.disconnect); - - this.listener.onApplicationEvent(this.deleted); - - verify(this.wsSession, times(0)).close(any(CloseStatus.class)); - } - - // gh-76 - @Test - @SuppressWarnings("unchecked") - public void onApplicationEventConnectDisconnectCleanup() { - this.listener.onApplicationEvent(this.connect); - - this.listener.onApplicationEvent(this.disconnect); - - Map> httpSessionIdToWsSessions = (Map>) ReflectionTestUtils - .getField(this.listener, "httpSessionIdToWsSessions"); - assertThat(httpSessionIdToWsSessions).isEmpty(); - } - - @Test - public void onApplicationEventConnectDisconnectNullSession() throws Exception { - this.listener.onApplicationEvent(this.connect); - this.attributes.clear(); - - this.listener.onApplicationEvent(this.disconnect); - - // no exception - } - - @Test - public void onApplicationEventConnectConnectDisonnect() throws Exception { - this.listener.onApplicationEvent(this.connect); - this.listener.onApplicationEvent(this.connect2); - this.listener.onApplicationEvent(this.disconnect); - - this.listener.onApplicationEvent(this.deleted); - - verify(this.wsSession2).close(WebSocketRegistryListener.SESSION_EXPIRED_STATUS); - verify(this.wsSession, times(0)).close(any(CloseStatus.class)); - } -} diff --git a/spring-session/src/test/java/org/springframework/session/web/socket/server/SessionRepositoryMessageInterceptorTests.java b/spring-session/src/test/java/org/springframework/session/web/socket/server/SessionRepositoryMessageInterceptorTests.java deleted file mode 100644 index 25abce1..0000000 --- a/spring-session/src/test/java/org/springframework/session/web/socket/server/SessionRepositoryMessageInterceptorTests.java +++ /dev/null @@ -1,297 +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.web.socket.server; - -import java.util.Collections; -import java.util.EnumSet; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.TimeUnit; - -import javax.servlet.http.HttpSession; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentMatcher; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; - -import org.springframework.http.server.ServletServerHttpRequest; -import org.springframework.messaging.Message; -import org.springframework.messaging.MessageChannel; -import org.springframework.messaging.simp.SimpMessageHeaderAccessor; -import org.springframework.messaging.simp.SimpMessageType; -import org.springframework.messaging.support.MessageBuilder; -import org.springframework.mock.web.MockHttpServletRequest; -import org.springframework.session.ExpiringSession; -import org.springframework.session.SessionRepository; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.longThat; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; - -@RunWith(MockitoJUnitRunner.class) -public class SessionRepositoryMessageInterceptorTests { - @Mock - SessionRepository sessionRepository; - @Mock - MessageChannel channel; - @Mock - ExpiringSession session; - - Message createMessage; - - SimpMessageHeaderAccessor headers; - - SessionRepositoryMessageInterceptor interceptor; - - @Before - public void setup() { - this.interceptor = new SessionRepositoryMessageInterceptor( - this.sessionRepository); - this.headers = SimpMessageHeaderAccessor.create(); - this.headers.setSessionId("session"); - this.headers.setSessionAttributes(new HashMap()); - setMessageType(SimpMessageType.MESSAGE); - String sessionId = "http-session"; - setSessionId(sessionId); - given(this.sessionRepository.getSession(sessionId)).willReturn(this.session); - } - - @Test(expected = IllegalArgumentException.class) - public void preSendconstructorNullRepository() { - new SessionRepositoryMessageInterceptor(null); - } - - @Test - public void preSendNullMessage() { - assertThat(this.interceptor.preSend(null, this.channel)).isNull(); - } - - @Test - public void preSendConnectAckDoesNotInvokeSessionRepository() { - setMessageType(SimpMessageType.CONNECT_ACK); - - assertThat(this.interceptor.preSend(createMessage(), this.channel)) - .isSameAs(this.createMessage); - - verifyZeroInteractions(this.sessionRepository); - } - - @Test - public void preSendHeartbeatDoesNotInvokeSessionRepository() { - setMessageType(SimpMessageType.HEARTBEAT); - - assertThat(this.interceptor.preSend(createMessage(), this.channel)) - .isSameAs(this.createMessage); - - verifyZeroInteractions(this.sessionRepository); - } - - @Test - public void preSendDisconnectDoesNotInvokeSessionRepository() { - setMessageType(SimpMessageType.DISCONNECT); - - assertThat(this.interceptor.preSend(createMessage(), this.channel)) - .isSameAs(this.createMessage); - - verifyZeroInteractions(this.sessionRepository); - } - - @Test - public void preSendOtherDoesNotInvokeSessionRepository() { - setMessageType(SimpMessageType.OTHER); - - assertThat(this.interceptor.preSend(createMessage(), this.channel)) - .isSameAs(this.createMessage); - - verifyZeroInteractions(this.sessionRepository); - } - - @Test(expected = IllegalArgumentException.class) - public void setMatchingMessageTypesNull() { - this.interceptor.setMatchingMessageTypes(null); - } - - @Test(expected = IllegalArgumentException.class) - public void setMatchingMessageTypesEmpty() { - this.interceptor.setMatchingMessageTypes(Collections.emptySet()); - } - - @Test - public void preSendSetMatchingMessageTypes() { - this.interceptor.setMatchingMessageTypes(EnumSet.of(SimpMessageType.DISCONNECT)); - setMessageType(SimpMessageType.DISCONNECT); - - assertThat(this.interceptor.preSend(createMessage(), this.channel)) - .isSameAs(this.createMessage); - - verify(this.sessionRepository).getSession(anyString()); - verify(this.sessionRepository).save(this.session); - } - - @Test - public void preSendConnectUpdatesLastUpdateTime() { - setMessageType(SimpMessageType.CONNECT); - - assertThat(this.interceptor.preSend(createMessage(), this.channel)) - .isSameAs(this.createMessage); - - verify(this.session).setLastAccessedTime(longThat(isAlmostNow())); - verify(this.sessionRepository).save(this.session); - } - - @Test - public void preSendMessageUpdatesLastUpdateTime() { - setMessageType(SimpMessageType.MESSAGE); - - assertThat(this.interceptor.preSend(createMessage(), this.channel)) - .isSameAs(this.createMessage); - - verify(this.session).setLastAccessedTime(longThat(isAlmostNow())); - verify(this.sessionRepository).save(this.session); - } - - @Test - public void preSendSubscribeUpdatesLastUpdateTime() { - setMessageType(SimpMessageType.SUBSCRIBE); - - assertThat(this.interceptor.preSend(createMessage(), this.channel)) - .isSameAs(this.createMessage); - - verify(this.session).setLastAccessedTime(longThat(isAlmostNow())); - verify(this.sessionRepository).save(this.session); - } - - @Test - public void preSendUnsubscribeUpdatesLastUpdateTime() { - setMessageType(SimpMessageType.UNSUBSCRIBE); - this.session.setLastAccessedTime(0L); - - assertThat(this.interceptor.preSend(createMessage(), this.channel)) - .isSameAs(this.createMessage); - - verify(this.session).setLastAccessedTime(longThat(isAlmostNow())); - verify(this.sessionRepository).save(this.session); - } - - // This will updated when SPR-12288 is resolved - @Test - public void preSendExpiredSession() { - setSessionId("expired"); - - this.interceptor.preSend(createMessage(), this.channel); - - verify(this.sessionRepository, times(0)).save(any(ExpiringSession.class)); - } - - @Test - public void preSendNullSessionId() { - setSessionId(null); - - assertThat(this.interceptor.preSend(createMessage(), this.channel)) - .isSameAs(this.createMessage); - - verifyZeroInteractions(this.sessionRepository); - } - - @Test - public void preSendNullSessionAttributes() { - this.headers.setSessionAttributes(null); - - assertThat(this.interceptor.preSend(createMessage(), this.channel)) - .isSameAs(this.createMessage); - - verifyZeroInteractions(this.sessionRepository); - } - - @Test - public void beforeHandshakeNotServletServerHttpRequest() throws Exception { - assertThat(this.interceptor.beforeHandshake(null, null, null, null)).isTrue(); - - verifyZeroInteractions(this.sessionRepository); - } - - @Test - public void beforeHandshakeNullSession() throws Exception { - ServletServerHttpRequest request = new ServletServerHttpRequest( - new MockHttpServletRequest()); - assertThat(this.interceptor.beforeHandshake(request, null, null, null)).isTrue(); - - verifyZeroInteractions(this.sessionRepository); - } - - @Test - public void beforeHandshakeSession() throws Exception { - MockHttpServletRequest httpRequest = new MockHttpServletRequest(); - HttpSession httpSession = httpRequest.getSession(); - ServletServerHttpRequest request = new ServletServerHttpRequest(httpRequest); - Map attributes = new HashMap(); - - assertThat(this.interceptor.beforeHandshake(request, null, null, attributes)) - .isTrue(); - - assertThat(attributes.size()).isEqualTo(1); - assertThat(SessionRepositoryMessageInterceptor.getSessionId(attributes)) - .isEqualTo(httpSession.getId()); - } - - /** - * At the moment there is no need for afterHandshake to do anything. - */ - @Test - public void afterHandshakeDoesNothing() { - this.interceptor.afterHandshake(null, null, null, null); - - verifyZeroInteractions(this.sessionRepository); - } - - private void setSessionId(String id) { - SessionRepositoryMessageInterceptor - .setSessionId(this.headers.getSessionAttributes(), id); - } - - private Message createMessage() { - this.createMessage = MessageBuilder.createMessage("", - this.headers.getMessageHeaders()); - return this.createMessage; - } - - private void setMessageType(SimpMessageType type) { - this.headers.setHeader(SimpMessageHeaderAccessor.MESSAGE_TYPE_HEADER, type); - } - - static AlmostNowMatcher isAlmostNow() { - return new AlmostNowMatcher(); - } - - static class AlmostNowMatcher implements ArgumentMatcher { - - public boolean matches(Long argument) { - long now = System.currentTimeMillis(); - long delta = now - argument; - return delta >= 0 && delta < TimeUnit.SECONDS.toMillis(3); - } - - } -} diff --git a/spring-session/src/test/resources/org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfigurationClassPathXmlApplicationContextTests-context.xml b/spring-session/src/test/resources/org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfigurationClassPathXmlApplicationContextTests-context.xml deleted file mode 100644 index 873638d..0000000 --- a/spring-session/src/test/resources/org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfigurationClassPathXmlApplicationContextTests-context.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - diff --git a/spring-session/src/test/resources/org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfigurationXmlCustomExpireTests-context.xml b/spring-session/src/test/resources/org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfigurationXmlCustomExpireTests-context.xml deleted file mode 100644 index 93382ab..0000000 --- a/spring-session/src/test/resources/org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfigurationXmlCustomExpireTests-context.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - diff --git a/spring-session/src/test/resources/org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfigurationXmlTests-context.xml b/spring-session/src/test/resources/org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfigurationXmlTests-context.xml deleted file mode 100644 index 0641c51..0000000 --- a/spring-session/src/test/resources/org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfigurationXmlTests-context.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - diff --git a/spring-session/src/test/resources/org/springframework/session/hazelcast/config/annotation/web/http/hazelcast-custom-idle-time-map-name.xml b/spring-session/src/test/resources/org/springframework/session/hazelcast/config/annotation/web/http/hazelcast-custom-idle-time-map-name.xml deleted file mode 100644 index ab14415..0000000 --- a/spring-session/src/test/resources/org/springframework/session/hazelcast/config/annotation/web/http/hazelcast-custom-idle-time-map-name.xml +++ /dev/null @@ -1,45 +0,0 @@ - - - - - spring-session-it-test-idle-time-map-name - test-pass - - - - 5701 - - 0 - - - - - - 127.0.0.1 - - 127.0.0.1 - - - - - - - - - BINARY - 1 - 0 - 0 - 300 - com.hazelcast.map.merge.PutIfAbsentMapMergePolicy - - principalName - - - principalName - - - - diff --git a/spring-session/src/test/resources/org/springframework/session/hazelcast/config/annotation/web/http/hazelcast-custom-map-name.xml b/spring-session/src/test/resources/org/springframework/session/hazelcast/config/annotation/web/http/hazelcast-custom-map-name.xml deleted file mode 100644 index 919fc2f..0000000 --- a/spring-session/src/test/resources/org/springframework/session/hazelcast/config/annotation/web/http/hazelcast-custom-map-name.xml +++ /dev/null @@ -1,45 +0,0 @@ - - - - - spring-session-it-test-map-name - test-pass - - - - 5701 - - 0 - - - - - - 127.0.0.1 - - 127.0.0.1 - - - - - - - - - BINARY - 1 - 0 - 0 - 0 - com.hazelcast.map.merge.PutIfAbsentMapMergePolicy - - principalName - - - principalName - - - - diff --git a/spring-session/src/test/resources/spring-session-cleanup-cron-expression-oops.properties b/spring-session/src/test/resources/spring-session-cleanup-cron-expression-oops.properties deleted file mode 100644 index 17db1ef..0000000 --- a/spring-session/src/test/resources/spring-session-cleanup-cron-expression-oops.properties +++ /dev/null @@ -1 +0,0 @@ -spring.session.cleanup.cron.expression=oops \ No newline at end of file diff --git a/spring-session/src/main/java/org/springframework/session/data/mongo/AbstractMongoSessionConverter.java b/src/main/java/org/springframework/session/data/mongo/AbstractMongoSessionConverter.java similarity index 86% rename from spring-session/src/main/java/org/springframework/session/data/mongo/AbstractMongoSessionConverter.java rename to src/main/java/org/springframework/session/data/mongo/AbstractMongoSessionConverter.java index 07e9b66..bcbeb98 100644 --- a/spring-session/src/main/java/org/springframework/session/data/mongo/AbstractMongoSessionConverter.java +++ b/src/main/java/org/springframework/session/data/mongo/AbstractMongoSessionConverter.java @@ -17,13 +17,10 @@ package org.springframework.session.data.mongo; import java.util.Collections; -import java.util.List; import java.util.Set; -import com.mongodb.DBObject; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; - import org.bson.Document; import org.springframework.core.convert.TypeDescriptor; @@ -36,6 +33,8 @@ import org.springframework.data.mongodb.core.query.Query; import org.springframework.session.FindByIndexNameSessionRepository; import org.springframework.session.Session; +import com.mongodb.DBObject; + /** * Base class for serializing and deserializing session objects. To create custom * serializer you have to implement this interface and simply register your class as a @@ -49,6 +48,7 @@ public abstract class AbstractMongoSessionConverter implements GenericConverter private static final Log LOG = LogFactory.getLog(AbstractMongoSessionConverter.class); protected static final String EXPIRE_AT_FIELD_NAME = "expireAt"; + private static final String SPRING_SECURITY_CONTEXT = "SPRING_SECURITY_CONTEXT"; /** @@ -69,39 +69,39 @@ public abstract class AbstractMongoSessionConverter implements GenericConverter * @param sessionCollectionIndexes {@link IndexOperations} to use */ protected void ensureIndexes(IndexOperations sessionCollectionIndexes) { - List indexInfo = sessionCollectionIndexes.getIndexInfo(); - for (IndexInfo info : indexInfo) { + + for (IndexInfo info : sessionCollectionIndexes.getIndexInfo()) { if (EXPIRE_AT_FIELD_NAME.equals(info.getName())) { - LOG.debug( - "TTL index on field " + EXPIRE_AT_FIELD_NAME + " already exists"); + LOG.debug("TTL index on field " + EXPIRE_AT_FIELD_NAME + " already exists"); return; } } + LOG.info("Creating TTL index on field " + EXPIRE_AT_FIELD_NAME); sessionCollectionIndexes - .ensureIndex(new Index(EXPIRE_AT_FIELD_NAME, Sort.Direction.ASC) - .named(EXPIRE_AT_FIELD_NAME).expire(0)); + .ensureIndex(new Index(EXPIRE_AT_FIELD_NAME, Sort.Direction.ASC).named(EXPIRE_AT_FIELD_NAME).expire(0)); } protected String extractPrincipal(Session expiringSession) { - String resolvedPrincipal = AuthenticationParser - .extractName(expiringSession.getAttribute(SPRING_SECURITY_CONTEXT)); + + String resolvedPrincipal = AuthenticationParser.extractName(expiringSession.getAttribute(SPRING_SECURITY_CONTEXT)); + if (resolvedPrincipal != null) { return resolvedPrincipal; - } - else { - return expiringSession.getAttribute( - FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME); + } else { + return expiringSession.getAttribute(FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME); } } public Set getConvertibleTypes() { + return Collections.singleton( new ConvertiblePair(DBObject.class, MongoExpiringSession.class)); } @SuppressWarnings("unchecked") public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { + if (source == null) { return null; } diff --git a/spring-session/src/main/java/org/springframework/session/data/mongo/AuthenticationParser.java b/src/main/java/org/springframework/session/data/mongo/AuthenticationParser.java similarity index 97% rename from spring-session/src/main/java/org/springframework/session/data/mongo/AuthenticationParser.java rename to src/main/java/org/springframework/session/data/mongo/AuthenticationParser.java index a65419b..a02fcca 100644 --- a/spring-session/src/main/java/org/springframework/session/data/mongo/AuthenticationParser.java +++ b/src/main/java/org/springframework/session/data/mongo/AuthenticationParser.java @@ -36,6 +36,7 @@ final class AuthenticationParser { * @return principal name */ static String extractName(Object authentication) { + if (authentication != null) { Expression expression = PARSER.parseExpression(NAME_EXPRESSION); return expression.getValue(authentication, String.class); @@ -43,6 +44,5 @@ final class AuthenticationParser { return null; } - private AuthenticationParser() { - } + private AuthenticationParser() {} } diff --git a/spring-session/src/main/java/org/springframework/session/data/mongo/JacksonMongoSessionConverter.java b/src/main/java/org/springframework/session/data/mongo/JacksonMongoSessionConverter.java similarity index 99% rename from spring-session/src/main/java/org/springframework/session/data/mongo/JacksonMongoSessionConverter.java rename to src/main/java/org/springframework/session/data/mongo/JacksonMongoSessionConverter.java index 2f641aa..99fd9d6 100644 --- a/spring-session/src/main/java/org/springframework/session/data/mongo/JacksonMongoSessionConverter.java +++ b/src/main/java/org/springframework/session/data/mongo/JacksonMongoSessionConverter.java @@ -18,6 +18,14 @@ package org.springframework.session.data.mongo; import java.io.IOException; import java.util.Collections; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.bson.Document; + +import org.springframework.data.mongodb.core.query.Criteria; +import org.springframework.data.mongodb.core.query.Query; +import org.springframework.session.FindByIndexNameSessionRepository; + import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.core.JsonProcessingException; @@ -28,14 +36,6 @@ import com.fasterxml.jackson.databind.PropertyNamingStrategy; import com.mongodb.DBObject; import com.mongodb.util.JSON; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.bson.Document; - -import org.springframework.data.mongodb.core.query.Criteria; -import org.springframework.data.mongodb.core.query.Query; -import org.springframework.session.FindByIndexNameSessionRepository; - /** * {@code AbstractMongoSessionConverter} implementation using Jackson. * @@ -56,13 +56,14 @@ public class JacksonMongoSessionConverter extends AbstractMongoSessionConverter } public JacksonMongoSessionConverter(Iterable modules) { + this.objectMapper = buildObjectMapper(); this.objectMapper.registerModules(modules); } protected Query getQueryForIndex(String indexName, Object indexValue) { - if (FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME - .equals(indexName)) { + + if (FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME.equals(indexName)) { return Query.query(Criteria.where(PRINCIPAL_FIELD_NAME).is(indexValue)); } return Query.query(Criteria.where(ATTRS_FIELD_NAME + @@ -70,6 +71,7 @@ public class JacksonMongoSessionConverter extends AbstractMongoSessionConverter } private ObjectMapper buildObjectMapper() { + ObjectMapper objectMapper = new ObjectMapper(); // serialize fields instead of properties @@ -80,11 +82,13 @@ public class JacksonMongoSessionConverter extends AbstractMongoSessionConverter objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); objectMapper.setPropertyNamingStrategy(new MongoIdNamingStrategy()); + return objectMapper; } @Override protected DBObject convert(MongoExpiringSession source) { + try { DBObject dbSession = (DBObject) JSON.parse(this.objectMapper.writeValueAsString(source)); dbSession.put(PRINCIPAL_FIELD_NAME, extractPrincipal(source)); @@ -97,6 +101,7 @@ public class JacksonMongoSessionConverter extends AbstractMongoSessionConverter @Override protected MongoExpiringSession convert(Document source) { + String json = JSON.serialize(source); try { diff --git a/spring-session/src/main/java/org/springframework/session/data/mongo/JdkMongoSessionConverter.java b/src/main/java/org/springframework/session/data/mongo/JdkMongoSessionConverter.java similarity index 97% rename from spring-session/src/main/java/org/springframework/session/data/mongo/JdkMongoSessionConverter.java rename to src/main/java/org/springframework/session/data/mongo/JdkMongoSessionConverter.java index c7ec6bf..5932d8a 100644 --- a/spring-session/src/main/java/org/springframework/session/data/mongo/JdkMongoSessionConverter.java +++ b/src/main/java/org/springframework/session/data/mongo/JdkMongoSessionConverter.java @@ -20,9 +20,6 @@ import java.util.Date; import java.util.HashMap; import java.util.Map; -import com.mongodb.BasicDBObject; -import com.mongodb.DBObject; - import org.bson.Document; import org.bson.types.Binary; @@ -35,6 +32,9 @@ import org.springframework.session.FindByIndexNameSessionRepository; import org.springframework.session.Session; import org.springframework.util.Assert; +import com.mongodb.BasicDBObject; +import com.mongodb.DBObject; + /** * {@code AbstractMongoSessionConverter} implementation using standard Java serialization. * @@ -48,8 +48,7 @@ public class JdkMongoSessionConverter extends AbstractMongoSessionConverter { private static final String CREATION_TIME = "created"; private static final String LAST_ACCESSED_TIME = "accessed"; private static final String MAX_INTERVAL = "interval"; - static final String ATTRIBUTES = "attr"; - + private static final String ATTRIBUTES = "attr"; private static final String PRINCIPAL_FIELD_NAME = "principal"; private final Converter serializer; @@ -61,6 +60,7 @@ public class JdkMongoSessionConverter extends AbstractMongoSessionConverter { public JdkMongoSessionConverter(Converter serializer, Converter deserializer) { + Assert.notNull(serializer, "serializer cannot be null"); Assert.notNull(deserializer, "deserializer cannot be null"); this.serializer = serializer; @@ -69,6 +69,7 @@ public class JdkMongoSessionConverter extends AbstractMongoSessionConverter { @Override public Query getQueryForIndex(String indexName, Object indexValue) { + if (FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME .equals(indexName)) { return Query.query(Criteria.where(PRINCIPAL_FIELD_NAME).is(indexValue)); @@ -78,6 +79,7 @@ public class JdkMongoSessionConverter extends AbstractMongoSessionConverter { @Override protected DBObject convert(MongoExpiringSession session) { + BasicDBObject basicDBObject = new BasicDBObject(); basicDBObject.put(ID, session.getId()); basicDBObject.put(CREATION_TIME, session.getCreationTime()); @@ -91,6 +93,7 @@ public class JdkMongoSessionConverter extends AbstractMongoSessionConverter { @Override protected MongoExpiringSession convert(Document sessionWrapper) { + MongoExpiringSession session = new MongoExpiringSession( sessionWrapper.getString(ID), sessionWrapper.getInteger(MAX_INTERVAL)); @@ -103,19 +106,26 @@ public class JdkMongoSessionConverter extends AbstractMongoSessionConverter { } private byte[] serializeAttributes(Session session) { - Map attributes = new HashMap(); + + Map attributes = new HashMap<>(); + for (String attrName : session.getAttributeNames()) { attributes.put(attrName, session.getAttribute(attrName)); } + return this.serializer.convert(attributes); } @SuppressWarnings("unchecked") private void deserializeAttributes(Document sessionWrapper, Session session) { + Object sessionAttributes = sessionWrapper.get(ATTRIBUTES); + byte[] attributesBytes = (sessionAttributes instanceof Binary ? ((Binary) sessionAttributes).getData() : (byte[]) sessionAttributes); + Map attributes = (Map) this.deserializer.convert(attributesBytes); + for (Map.Entry entry : attributes.entrySet()) { session.setAttribute(entry.getKey(), entry.getValue()); } diff --git a/spring-session/src/main/java/org/springframework/session/data/mongo/MongoExpiringSession.java b/src/main/java/org/springframework/session/data/mongo/MongoExpiringSession.java similarity index 95% rename from spring-session/src/main/java/org/springframework/session/data/mongo/MongoExpiringSession.java rename to src/main/java/org/springframework/session/data/mongo/MongoExpiringSession.java index 6fcc22b..fd049fc 100644 --- a/spring-session/src/main/java/org/springframework/session/data/mongo/MongoExpiringSession.java +++ b/src/main/java/org/springframework/session/data/mongo/MongoExpiringSession.java @@ -34,7 +34,7 @@ import org.springframework.session.ExpiringSession; public class MongoExpiringSession implements ExpiringSession { /** - * Mongo doesn't support {@literal dot} in field names. We replace it with very rarely used character + * Mongo doesn't support {@literal dot} in field names. We replace it with a very rarely used character */ private static final char DOT_COVER_CHAR = '\uF607'; @@ -54,6 +54,7 @@ public class MongoExpiringSession implements ExpiringSession { } public MongoExpiringSession(String id, int maxInactiveIntervalInSeconds) { + this.id = id; this.interval = maxInactiveIntervalInSeconds; setLastAccessedTime(this.created); @@ -69,18 +70,21 @@ public class MongoExpiringSession implements ExpiringSession { } public Set getAttributeNames() { - HashSet result = new HashSet(); + + HashSet result = new HashSet<>(); + for (String key : this.attrs.keySet()) { result.add(uncoverDot(key)); } + return result; } public void setAttribute(String attributeName, Object attributeValue) { + if (attributeValue == null) { removeAttribute(coverDot(attributeName)); - } - else { + } else { this.attrs.put(coverDot(attributeName), attributeValue); } } @@ -98,9 +102,9 @@ public class MongoExpiringSession implements ExpiringSession { } public void setLastAccessedTime(long lastAccessedTime) { + this.accessed = lastAccessedTime; - this.expireAt = new Date( - lastAccessedTime + TimeUnit.SECONDS.toMillis(this.interval)); + this.expireAt = new Date(lastAccessedTime + TimeUnit.SECONDS.toMillis(this.interval)); } public long getLastAccessedTime() { @@ -137,6 +141,7 @@ public class MongoExpiringSession implements ExpiringSession { @Override public boolean equals(Object o) { + if (this == o) { return true; } diff --git a/spring-session/src/main/java/org/springframework/session/data/mongo/MongoOperationsSessionRepository.java b/src/main/java/org/springframework/session/data/mongo/MongoOperationsSessionRepository.java similarity index 95% rename from spring-session/src/main/java/org/springframework/session/data/mongo/MongoOperationsSessionRepository.java rename to src/main/java/org/springframework/session/data/mongo/MongoOperationsSessionRepository.java index 75536d5..a7550b8 100644 --- a/spring-session/src/main/java/org/springframework/session/data/mongo/MongoOperationsSessionRepository.java +++ b/src/main/java/org/springframework/session/data/mongo/MongoOperationsSessionRepository.java @@ -23,8 +23,6 @@ import java.util.Map; import javax.annotation.PostConstruct; -import com.mongodb.DBObject; - import org.bson.Document; import org.springframework.core.convert.TypeDescriptor; @@ -33,6 +31,8 @@ import org.springframework.data.mongodb.core.MongoOperations; import org.springframework.data.mongodb.core.query.Query; import org.springframework.session.FindByIndexNameSessionRepository; +import com.mongodb.DBObject; + /** * Session repository implementation which stores sessions in Mongo. Uses * {@link AbstractMongoSessionConverter} to transform session objects from/to native Mongo @@ -70,28 +70,37 @@ public class MongoOperationsSessionRepository } public MongoExpiringSession createSession() { + MongoExpiringSession session = new MongoExpiringSession(); + if (this.maxInactiveIntervalInSeconds != null) { session.setMaxInactiveIntervalInSeconds(this.maxInactiveIntervalInSeconds); } + return session; } public void save(MongoExpiringSession session) { + DBObject sessionDbObject = convertToDBObject(session); this.mongoOperations.save(sessionDbObject, this.collectionName); } public MongoExpiringSession getSession(String id) { + Document sessionWrapper = findSession(id); + if (sessionWrapper == null) { return null; } + MongoExpiringSession session = convertToSession(sessionWrapper); + if (session.isExpired()) { delete(id); return null; } + return session; } @@ -104,18 +113,23 @@ public class MongoOperationsSessionRepository * @param indexValue the value of the index to search for. * @return sessions map */ - public Map findByIndexNameAndIndexValue( - String indexName, String indexValue) { + public Map findByIndexNameAndIndexValue(String indexName, String indexValue) { + HashMap result = new HashMap(); + Query query = this.mongoSessionConverter.getQueryForIndex(indexName, indexValue); + if (query == null) { return Collections.emptyMap(); } + List mapSessions = this.mongoOperations.find(query, Document.class, this.collectionName); + for (Document dbSession : mapSessions) { MongoExpiringSession mapSession = convertToSession(dbSession); result.put(mapSession.getId(), mapSession); } + return result; } @@ -125,8 +139,8 @@ public class MongoOperationsSessionRepository @PostConstruct public void ensureIndexesAreCreated() { - IndexOperations indexOperations = this.mongoOperations - .indexOps(this.collectionName); + + IndexOperations indexOperations = this.mongoOperations.indexOps(this.collectionName); this.mongoSessionConverter.ensureIndexes(indexOperations); } @@ -135,19 +149,20 @@ public class MongoOperationsSessionRepository } MongoExpiringSession convertToSession(Document session) { + return (MongoExpiringSession) this.mongoSessionConverter.convert(session, TypeDescriptor.valueOf(Document.class), TypeDescriptor.valueOf(MongoExpiringSession.class)); } DBObject convertToDBObject(MongoExpiringSession session) { + return (DBObject) this.mongoSessionConverter.convert(session, TypeDescriptor.valueOf(MongoExpiringSession.class), TypeDescriptor.valueOf(DBObject.class)); } - public void setMongoSessionConverter( - AbstractMongoSessionConverter mongoSessionConverter) { + public void setMongoSessionConverter(AbstractMongoSessionConverter mongoSessionConverter) { this.mongoSessionConverter = mongoSessionConverter; } diff --git a/spring-session/src/main/java/org/springframework/session/data/mongo/SessionConverterProvider.java b/src/main/java/org/springframework/session/data/mongo/SessionConverterProvider.java similarity index 99% rename from spring-session/src/main/java/org/springframework/session/data/mongo/SessionConverterProvider.java rename to src/main/java/org/springframework/session/data/mongo/SessionConverterProvider.java index 7addcf6..b9f5131 100644 --- a/spring-session/src/main/java/org/springframework/session/data/mongo/SessionConverterProvider.java +++ b/src/main/java/org/springframework/session/data/mongo/SessionConverterProvider.java @@ -30,6 +30,7 @@ final class SessionConverterProvider { } static AbstractMongoSessionConverter getDefaultMongoConverter() { + if (ClassUtils.isPresent(JACKSON_CLASS_NAME, null)) { return new JacksonMongoSessionConverter(); } diff --git a/spring-session/src/main/java/org/springframework/session/data/mongo/config/annotation/web/http/EnableMongoHttpSession.java b/src/main/java/org/springframework/session/data/mongo/config/annotation/web/http/EnableMongoHttpSession.java similarity index 100% rename from spring-session/src/main/java/org/springframework/session/data/mongo/config/annotation/web/http/EnableMongoHttpSession.java rename to src/main/java/org/springframework/session/data/mongo/config/annotation/web/http/EnableMongoHttpSession.java diff --git a/spring-session/src/main/java/org/springframework/session/data/mongo/config/annotation/web/http/MongoHttpSessionConfiguration.java b/src/main/java/org/springframework/session/data/mongo/config/annotation/web/http/MongoHttpSessionConfiguration.java similarity index 90% rename from spring-session/src/main/java/org/springframework/session/data/mongo/config/annotation/web/http/MongoHttpSessionConfiguration.java rename to src/main/java/org/springframework/session/data/mongo/config/annotation/web/http/MongoHttpSessionConfiguration.java index 9922e98..b348384 100644 --- a/spring-session/src/main/java/org/springframework/session/data/mongo/config/annotation/web/http/MongoHttpSessionConfiguration.java +++ b/src/main/java/org/springframework/session/data/mongo/config/annotation/web/http/MongoHttpSessionConfiguration.java @@ -49,17 +49,19 @@ public class MongoHttpSessionConfiguration extends SpringHttpSessionConfiguratio private StringValueResolver embeddedValueResolver; @Bean - public MongoOperationsSessionRepository mongoSessionRepository( - MongoOperations mongoOperations) { - MongoOperationsSessionRepository repository = new MongoOperationsSessionRepository( - mongoOperations); + public MongoOperationsSessionRepository mongoSessionRepository(MongoOperations mongoOperations) { + + MongoOperationsSessionRepository repository = new MongoOperationsSessionRepository(mongoOperations); repository.setMaxInactiveIntervalInSeconds(this.maxInactiveIntervalInSeconds); + if (this.mongoSessionConverter != null) { repository.setMongoSessionConverter(this.mongoSessionConverter); } + if (StringUtils.hasText(this.collectionName)) { repository.setCollectionName(this.collectionName); } + return repository; } @@ -72,10 +74,12 @@ public class MongoHttpSessionConfiguration extends SpringHttpSessionConfiguratio } public void setImportMetadata(AnnotationMetadata importMetadata) { - AnnotationAttributes attributes = AnnotationAttributes.fromMap(importMetadata - .getAnnotationAttributes(EnableMongoHttpSession.class.getName())); - this.maxInactiveIntervalInSeconds = attributes - .getNumber("maxInactiveIntervalInSeconds"); + + AnnotationAttributes attributes = AnnotationAttributes.fromMap( + importMetadata.getAnnotationAttributes(EnableMongoHttpSession.class.getName())); + + this.maxInactiveIntervalInSeconds = attributes.getNumber("maxInactiveIntervalInSeconds"); + String collectionNameValue = attributes.getString("collectionName"); if (StringUtils.hasText(collectionNameValue)) { this.collectionName = this.embeddedValueResolver.resolveStringValue(collectionNameValue); @@ -83,8 +87,7 @@ public class MongoHttpSessionConfiguration extends SpringHttpSessionConfiguratio } @Autowired(required = false) - public void setMongoSessionConverter( - AbstractMongoSessionConverter mongoSessionConverter) { + public void setMongoSessionConverter(AbstractMongoSessionConverter mongoSessionConverter) { this.mongoSessionConverter = mongoSessionConverter; } diff --git a/spring-session/src/test/java/org/springframework/session/data/mongo/AuthenticationParserTests.java b/src/test/java/org/springframework/session/data/mongo/AuthenticationParserTest.java similarity index 86% rename from spring-session/src/test/java/org/springframework/session/data/mongo/AuthenticationParserTests.java rename to src/test/java/org/springframework/session/data/mongo/AuthenticationParserTest.java index cfbd170..16fa982 100644 --- a/spring-session/src/test/java/org/springframework/session/data/mongo/AuthenticationParserTests.java +++ b/src/test/java/org/springframework/session/data/mongo/AuthenticationParserTest.java @@ -15,25 +15,25 @@ */ package org.springframework.session.data.mongo; +import static org.assertj.core.api.Assertions.*; + import org.junit.Test; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.context.SecurityContextImpl; -import static org.assertj.core.api.Assertions.assertThat; - /** * @author Jakub Kubrynski */ -public class AuthenticationParserTests { +public class AuthenticationParserTest { @Test public void shouldExtractName() { + // given String principalName = "john_the_springer"; SecurityContextImpl context = new SecurityContextImpl(); - context.setAuthentication( - new UsernamePasswordAuthenticationToken(principalName, null)); + context.setAuthentication(new UsernamePasswordAuthenticationToken(principalName, null)); // when String extractedName = AuthenticationParser.extractName(context); diff --git a/spring-session/src/test/java/org/springframework/session/data/mongo/JacksonMongoSessionConverterTest.java b/src/test/java/org/springframework/session/data/mongo/JacksonMongoSessionConverterTest.java similarity index 96% rename from spring-session/src/test/java/org/springframework/session/data/mongo/JacksonMongoSessionConverterTest.java rename to src/test/java/org/springframework/session/data/mongo/JacksonMongoSessionConverterTest.java index dc3bbf1..27c093a 100644 --- a/spring-session/src/test/java/org/springframework/session/data/mongo/JacksonMongoSessionConverterTest.java +++ b/src/test/java/org/springframework/session/data/mongo/JacksonMongoSessionConverterTest.java @@ -15,12 +15,13 @@ */ package org.springframework.session.data.mongo; -import com.mongodb.DBObject; +import static org.assertj.core.api.Assertions.*; + import org.junit.Test; import org.springframework.data.mongodb.core.query.Query; -import static org.assertj.core.api.Assertions.assertThat; +import com.mongodb.DBObject; /** * @author Jakub Kubrynski @@ -31,6 +32,7 @@ public class JacksonMongoSessionConverterTest { @Test public void shouldSaveIdField() throws Exception { + //given MongoExpiringSession session = new MongoExpiringSession(); @@ -44,6 +46,7 @@ public class JacksonMongoSessionConverterTest { @Test public void shouldQueryAgainstAttribute() throws Exception { + //when Query cart = this.sut.getQueryForIndex("cart", "my-cart"); diff --git a/spring-session/src/test/java/org/springframework/session/data/mongo/JdkMongoSessionConverterTests.java b/src/test/java/org/springframework/session/data/mongo/JdkMongoSessionConverterTest.java similarity index 97% rename from spring-session/src/test/java/org/springframework/session/data/mongo/JdkMongoSessionConverterTests.java rename to src/test/java/org/springframework/session/data/mongo/JdkMongoSessionConverterTest.java index bd206e3..fa58fdf 100644 --- a/spring-session/src/test/java/org/springframework/session/data/mongo/JdkMongoSessionConverterTests.java +++ b/src/test/java/org/springframework/session/data/mongo/JdkMongoSessionConverterTest.java @@ -15,7 +15,8 @@ */ package org.springframework.session.data.mongo; -import com.mongodb.DBObject; +import static org.assertj.core.api.Assertions.*; + import org.junit.Test; import org.springframework.core.convert.TypeDescriptor; @@ -26,13 +27,13 @@ import org.springframework.security.core.context.SecurityContextImpl; import org.springframework.session.ExpiringSession; import org.springframework.session.FindByIndexNameSessionRepository; -import static org.assertj.core.api.Assertions.assertThat; +import com.mongodb.DBObject; /** * @author Jakub Kubrynski * @author Rob Winch */ -public class JdkMongoSessionConverterTests { +public class JdkMongoSessionConverterTest { JdkMongoSessionConverter sut = new JdkMongoSessionConverter(); @@ -48,6 +49,7 @@ public class JdkMongoSessionConverterTests { @Test public void verifyRoundTripSerialization() throws Exception { + // given MongoExpiringSession toSerialize = new MongoExpiringSession(); toSerialize.setAttribute("username", "john_the_springer"); @@ -62,6 +64,7 @@ public class JdkMongoSessionConverterTests { @Test public void shouldExtractPrincipalNameFromAttributes() throws Exception { + // given MongoExpiringSession toSerialize = new MongoExpiringSession(); String principalName = "john_the_springer"; @@ -78,6 +81,7 @@ public class JdkMongoSessionConverterTests { @Test public void shouldExtractPrincipalNameFromAuthentication() throws Exception { + // given MongoExpiringSession toSerialize = new MongoExpiringSession(); String principalName = "john_the_springer"; diff --git a/spring-session/src/test/java/org/springframework/session/data/mongo/MongoExpiringSessionTests.java b/src/test/java/org/springframework/session/data/mongo/MongoExpiringSessionTest.java similarity index 96% rename from spring-session/src/test/java/org/springframework/session/data/mongo/MongoExpiringSessionTests.java rename to src/test/java/org/springframework/session/data/mongo/MongoExpiringSessionTest.java index 46e11e5..20ddc83 100644 --- a/spring-session/src/test/java/org/springframework/session/data/mongo/MongoExpiringSessionTests.java +++ b/src/test/java/org/springframework/session/data/mongo/MongoExpiringSessionTest.java @@ -23,7 +23,7 @@ import static org.assertj.core.api.Assertions.assertThat; /** * @author Rob Winch */ -public class MongoExpiringSessionTests { +public class MongoExpiringSessionTest { @Test public void isExpiredWhenIntervalNegativeThenFalse() { diff --git a/spring-session/src/test/java/org/springframework/session/data/mongo/MongoOperationsSessionRepositoryTests.java b/src/test/java/org/springframework/session/data/mongo/MongoOperationsSessionRepositoryTest.java similarity index 97% rename from spring-session/src/test/java/org/springframework/session/data/mongo/MongoOperationsSessionRepositoryTests.java rename to src/test/java/org/springframework/session/data/mongo/MongoOperationsSessionRepositoryTest.java index a2fe508..efd2fde 100644 --- a/spring-session/src/test/java/org/springframework/session/data/mongo/MongoOperationsSessionRepositoryTests.java +++ b/src/test/java/org/springframework/session/data/mongo/MongoOperationsSessionRepositoryTest.java @@ -16,12 +16,18 @@ package org.springframework.session.data.mongo; +import static org.assertj.core.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.BDDMockito.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + import java.util.Collections; import java.util.Map; import java.util.UUID; -import com.mongodb.BasicDBObject; -import com.mongodb.DBObject; import org.bson.Document; import org.junit.Before; import org.junit.Test; @@ -35,13 +41,8 @@ import org.springframework.data.mongodb.core.query.Query; import org.springframework.session.ExpiringSession; import org.springframework.session.FindByIndexNameSessionRepository; -import static org.assertj.core.api.Assertions.assertThat; -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.mock; -import static org.mockito.Mockito.verify; +import com.mongodb.BasicDBObject; +import com.mongodb.DBObject; /** * Tests for {@link MongoOperationsSessionRepository}. @@ -50,7 +51,7 @@ import static org.mockito.Mockito.verify; * @author Vedran Pavic */ @RunWith(MockitoJUnitRunner.class) -public class MongoOperationsSessionRepositoryTests { +public class MongoOperationsSessionRepositoryTest { @Mock private AbstractMongoSessionConverter converter; diff --git a/spring-session/src/test/java/org/springframework/session/data/mongo/config/annotation/web/http/MongoHttpSessionConfigurationTests.java b/src/test/java/org/springframework/session/data/mongo/config/annotation/web/http/MongoHttpSessionConfigurationTest.java similarity index 87% rename from spring-session/src/test/java/org/springframework/session/data/mongo/config/annotation/web/http/MongoHttpSessionConfigurationTests.java rename to src/test/java/org/springframework/session/data/mongo/config/annotation/web/http/MongoHttpSessionConfigurationTest.java index 16e22ed..7fd66b5 100644 --- a/spring-session/src/test/java/org/springframework/session/data/mongo/config/annotation/web/http/MongoHttpSessionConfigurationTests.java +++ b/src/test/java/org/springframework/session/data/mongo/config/annotation/web/http/MongoHttpSessionConfigurationTest.java @@ -15,6 +15,10 @@ */ package org.springframework.session.data.mongo.config.annotation.web.http; +import static org.assertj.core.api.Assertions.*; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.BDDMockito.*; + import java.net.UnknownHostException; import org.junit.After; @@ -35,18 +39,13 @@ import org.springframework.session.data.mongo.AbstractMongoSessionConverter; import org.springframework.session.data.mongo.MongoOperationsSessionRepository; import org.springframework.test.util.ReflectionTestUtils; -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.mock; - /** * Tests for {@link MongoHttpSessionConfiguration}. * * @author Eddú Meléndez * @author Vedran Pavic */ -public class MongoHttpSessionConfigurationTests { +public class MongoHttpSessionConfigurationTest { private static final String COLLECTION_NAME = "testSessions"; @@ -59,6 +58,7 @@ public class MongoHttpSessionConfigurationTests { @After public void after() { + if (this.context != null) { this.context.close(); } @@ -66,6 +66,7 @@ public class MongoHttpSessionConfigurationTests { @Test public void noMongoOperationsConfiguration() { + this.thrown.expect(UnsatisfiedDependencyException.class); this.thrown.expectMessage("mongoSessionRepository"); @@ -74,51 +75,56 @@ public class MongoHttpSessionConfigurationTests { @Test public void defaultConfiguration() { + registerAndRefresh(DefaultConfiguration.class); assertThat(this.context.getBean(MongoOperationsSessionRepository.class)) - .isNotNull(); + .isNotNull(); } @Test public void customCollectionName() { + registerAndRefresh(CustomCollectionNameConfiguration.class); - MongoOperationsSessionRepository repository = this.context - .getBean(MongoOperationsSessionRepository.class); + MongoOperationsSessionRepository repository = this.context.getBean(MongoOperationsSessionRepository.class); + assertThat(repository).isNotNull(); assertThat(ReflectionTestUtils.getField(repository, "collectionName")) - .isEqualTo(COLLECTION_NAME); + .isEqualTo(COLLECTION_NAME); } @Test public void setCustomCollectionName() { + registerAndRefresh(CustomCollectionNameSetConfiguration.class); - MongoHttpSessionConfiguration session = this.context - .getBean(MongoHttpSessionConfiguration.class); + MongoHttpSessionConfiguration session = this.context.getBean(MongoHttpSessionConfiguration.class); + assertThat(session).isNotNull(); assertThat(ReflectionTestUtils.getField(session, "collectionName")) - .isEqualTo(COLLECTION_NAME); + .isEqualTo(COLLECTION_NAME); } @Test public void customMaxInactiveIntervalInSeconds() { + registerAndRefresh(CustomMaxInactiveIntervalInSecondsConfiguration.class); - MongoOperationsSessionRepository repository = this.context - .getBean(MongoOperationsSessionRepository.class); + MongoOperationsSessionRepository repository = this.context.getBean(MongoOperationsSessionRepository.class); + assertThat(repository).isNotNull(); assertThat(ReflectionTestUtils.getField(repository, "maxInactiveIntervalInSeconds")) - .isEqualTo(MAX_INACTIVE_INTERVAL_IN_SECONDS); + .isEqualTo(MAX_INACTIVE_INTERVAL_IN_SECONDS); } @Test public void setCustomMaxInactiveIntervalInSeconds() { + registerAndRefresh(CustomMaxInactiveIntervalInSecondsSetConfiguration.class); - MongoOperationsSessionRepository repository = this.context - .getBean(MongoOperationsSessionRepository.class); + MongoOperationsSessionRepository repository = this.context.getBean(MongoOperationsSessionRepository.class); + assertThat(repository).isNotNull(); assertThat(ReflectionTestUtils.getField(repository, "maxInactiveIntervalInSeconds")) .isEqualTo(MAX_INACTIVE_INTERVAL_IN_SECONDS); @@ -126,12 +132,12 @@ public class MongoHttpSessionConfigurationTests { @Test public void setCustomSessionConverterConfiguration() { + registerAndRefresh(CustomSessionConverterConfiguration.class); - MongoOperationsSessionRepository repository = this.context - .getBean(MongoOperationsSessionRepository.class); - AbstractMongoSessionConverter mongoSessionConverter = this.context - .getBean(AbstractMongoSessionConverter.class); + MongoOperationsSessionRepository repository = this.context.getBean(MongoOperationsSessionRepository.class); + AbstractMongoSessionConverter mongoSessionConverter = this.context.getBean(AbstractMongoSessionConverter.class); + assertThat(repository).isNotNull(); assertThat(mongoSessionConverter).isNotNull(); assertThat(ReflectionTestUtils.getField(repository, "mongoSessionConverter")) @@ -140,13 +146,18 @@ public class MongoHttpSessionConfigurationTests { @Test public void resolveCollectionNameByPropertyPlaceholder() { + this.context.setEnvironment(new MockEnvironment().withProperty("session.mongo.collectionName", COLLECTION_NAME)); registerAndRefresh(CustomMongoJdbcSessionConfiguration.class); + MongoHttpSessionConfiguration configuration = this.context.getBean(MongoHttpSessionConfiguration.class); - assertThat(ReflectionTestUtils.getField(configuration, "collectionName")).isEqualTo(COLLECTION_NAME); + + assertThat(ReflectionTestUtils.getField(configuration, "collectionName")) + .isEqualTo(COLLECTION_NAME); } private void registerAndRefresh(Class... annotatedClasses) { + this.context.register(annotatedClasses); this.context.refresh(); } @@ -161,9 +172,12 @@ public class MongoHttpSessionConfigurationTests { @Bean public MongoOperations mongoOperations() throws UnknownHostException { + MongoOperations mongoOperations = mock(MongoOperations.class); IndexOperations indexOperations = mock(IndexOperations.class); + given(mongoOperations.indexOps(anyString())).willReturn(indexOperations); + return mongoOperations; } diff --git a/spring-session/src/integration-test/java/org/springframework/session/data/AbstractITests.java b/src/test/java/org/springframework/session/data/mongo/integration/AbstractITest.java similarity index 95% rename from spring-session/src/integration-test/java/org/springframework/session/data/AbstractITests.java rename to src/test/java/org/springframework/session/data/mongo/integration/AbstractITest.java index 35b9fe5..ec48ecb 100644 --- a/spring-session/src/integration-test/java/org/springframework/session/data/AbstractITests.java +++ b/src/test/java/org/springframework/session/data/mongo/integration/AbstractITest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.session.data; +package org.springframework.session.data.mongo.integration; import java.util.UUID; @@ -35,7 +35,7 @@ import org.springframework.test.context.web.WebAppConfiguration; */ @RunWith(SpringJUnit4ClassRunner.class) @WebAppConfiguration -public abstract class AbstractITests { +public abstract class AbstractITest { protected SecurityContext context; @@ -46,9 +46,11 @@ public abstract class AbstractITests { @Before public void setup() { + if (this.registry != null) { this.registry.clear(); } + this.context = SecurityContextHolder.createEmptyContext(); this.context.setAuthentication( new UsernamePasswordAuthenticationToken("username-" + UUID.randomUUID(), diff --git a/spring-session/src/integration-test/java/org/springframework/session/data/mongo/AbstractMongoRepositoryITests.java b/src/test/java/org/springframework/session/data/mongo/integration/AbstractMongoRepositoryITest.java similarity index 96% rename from spring-session/src/integration-test/java/org/springframework/session/data/mongo/AbstractMongoRepositoryITests.java rename to src/test/java/org/springframework/session/data/mongo/integration/AbstractMongoRepositoryITest.java index 31be3ff..dcabf74 100644 --- a/spring-session/src/integration-test/java/org/springframework/session/data/mongo/AbstractMongoRepositoryITests.java +++ b/src/test/java/org/springframework/session/data/mongo/integration/AbstractMongoRepositoryITest.java @@ -13,7 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.session.data.mongo; +package org.springframework.session.data.mongo.integration; + +import static org.assertj.core.api.Assertions.*; import java.io.IOException; import java.net.UnknownHostException; @@ -21,7 +23,6 @@ import java.util.Map; import java.util.UUID; import java.util.concurrent.TimeUnit; -import com.mongodb.MongoClient; import de.flapdoodle.embed.mongo.MongodExecutable; import org.junit.Test; @@ -37,18 +38,19 @@ import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.session.FindByIndexNameSessionRepository; import org.springframework.session.Session; -import org.springframework.session.data.AbstractITests; +import org.springframework.session.data.mongo.MongoExpiringSession; +import org.springframework.session.data.mongo.MongoOperationsSessionRepository; import org.springframework.util.SocketUtils; -import static org.assertj.core.api.Assertions.assertThat; +import com.mongodb.MongoClient; /** - * Abstract base class for {@link MongoOperationsSessionRepository} tests. + * Abstract base class for {@link org.springframework.session.data.mongo.MongoOperationsSessionRepository} tests. * * @author Jakub Kubrynski * @author Vedran Pavic */ -abstract public class AbstractMongoRepositoryITests extends AbstractITests { +abstract public class AbstractMongoRepositoryITest extends AbstractITest { protected static final String SPRING_SECURITY_CONTEXT = "SPRING_SECURITY_CONTEXT"; @@ -89,6 +91,7 @@ abstract public class AbstractMongoRepositoryITests extends AbstractITests { @Test public void putAllOnSingleAttrDoesNotRemoveOld() { + MongoExpiringSession toSave = this.repository.createSession(); toSave.setAttribute("a", "b"); @@ -110,6 +113,7 @@ abstract public class AbstractMongoRepositoryITests extends AbstractITests { @Test public void findByPrincipalName() throws Exception { + String principalName = "findByPrincipalName" + UUID.randomUUID(); MongoExpiringSession toSave = this.repository.createSession(); toSave.setAttribute(INDEX_NAME, principalName); @@ -133,6 +137,7 @@ abstract public class AbstractMongoRepositoryITests extends AbstractITests { @Test public void findByPrincipalNameNoPrincipalNameChange() throws Exception { + String principalName = "findByPrincipalNameNoPrincipalNameChange" + UUID.randomUUID(); MongoExpiringSession toSave = this.repository.createSession(); @@ -152,6 +157,7 @@ abstract public class AbstractMongoRepositoryITests extends AbstractITests { @Test public void findByPrincipalNameNoPrincipalNameChangeReload() throws Exception { + String principalName = "findByPrincipalNameNoPrincipalNameChangeReload" + UUID.randomUUID(); MongoExpiringSession toSave = this.repository.createSession(); @@ -173,6 +179,7 @@ abstract public class AbstractMongoRepositoryITests extends AbstractITests { @Test public void findByDeletedPrincipalName() throws Exception { + String principalName = "findByDeletedPrincipalName" + UUID.randomUUID(); MongoExpiringSession toSave = this.repository.createSession(); toSave.setAttribute(INDEX_NAME, principalName); @@ -190,6 +197,7 @@ abstract public class AbstractMongoRepositoryITests extends AbstractITests { @Test public void findByChangedPrincipalName() throws Exception { + String principalName = "findByChangedPrincipalName" + UUID.randomUUID(); String principalNameChanged = "findByChangedPrincipalName" + UUID.randomUUID(); MongoExpiringSession toSave = this.repository.createSession(); @@ -213,6 +221,7 @@ abstract public class AbstractMongoRepositoryITests extends AbstractITests { @Test public void findByDeletedPrincipalNameReload() throws Exception { + String principalName = "findByDeletedPrincipalName" + UUID.randomUUID(); MongoExpiringSession toSave = this.repository.createSession(); toSave.setAttribute(INDEX_NAME, principalName); @@ -231,6 +240,7 @@ abstract public class AbstractMongoRepositoryITests extends AbstractITests { @Test public void findByChangedPrincipalNameReload() throws Exception { + String principalName = "findByChangedPrincipalName" + UUID.randomUUID(); String principalNameChanged = "findByChangedPrincipalName" + UUID.randomUUID(); MongoExpiringSession toSave = this.repository.createSession(); @@ -256,6 +266,7 @@ abstract public class AbstractMongoRepositoryITests extends AbstractITests { @Test public void findBySecurityPrincipalName() throws Exception { + MongoExpiringSession toSave = this.repository.createSession(); toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.context); @@ -278,6 +289,7 @@ abstract public class AbstractMongoRepositoryITests extends AbstractITests { @Test public void findByPrincipalNameNoSecurityPrincipalNameChange() throws Exception { + MongoExpiringSession toSave = this.repository.createSession(); toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.context); @@ -295,6 +307,7 @@ abstract public class AbstractMongoRepositoryITests extends AbstractITests { @Test public void findByDeletedSecurityPrincipalName() throws Exception { + MongoExpiringSession toSave = this.repository.createSession(); toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.context); @@ -311,6 +324,7 @@ abstract public class AbstractMongoRepositoryITests extends AbstractITests { @Test public void findByChangedSecurityPrincipalName() throws Exception { + MongoExpiringSession toSave = this.repository.createSession(); toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.context); @@ -332,6 +346,7 @@ abstract public class AbstractMongoRepositoryITests extends AbstractITests { @Test public void findByChangedSecurityPrincipalNameReload() throws Exception { + MongoExpiringSession toSave = this.repository.createSession(); toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.context); @@ -355,6 +370,7 @@ abstract public class AbstractMongoRepositoryITests extends AbstractITests { @Test public void loadExpiredSession() throws Exception { + // given MongoExpiringSession expiredSession = this.repository.createSession(); long thirtyOneMinutesAgo = System.currentTimeMillis() @@ -388,6 +404,7 @@ abstract public class AbstractMongoRepositoryITests extends AbstractITests { @Bean @DependsOn("embeddedMongoServer") public MongoOperations mongoOperations() throws UnknownHostException { + MongoClient mongo = new MongoClient("localhost", this.embeddedMongoPort); return new MongoTemplate(mongo, "test"); } diff --git a/spring-session/src/integration-test/java/org/springframework/session/data/mongo/MongoITestUtils.java b/src/test/java/org/springframework/session/data/mongo/integration/MongoITestUtils.java similarity index 96% rename from spring-session/src/integration-test/java/org/springframework/session/data/mongo/MongoITestUtils.java rename to src/test/java/org/springframework/session/data/mongo/integration/MongoITestUtils.java index fa4f94f..c1008f4 100644 --- a/spring-session/src/integration-test/java/org/springframework/session/data/mongo/MongoITestUtils.java +++ b/src/test/java/org/springframework/session/data/mongo/integration/MongoITestUtils.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.session.data.mongo; +package org.springframework.session.data.mongo.integration; import java.io.IOException; @@ -42,11 +42,14 @@ final class MongoITestUtils { * @throws IOException in case of I/O errors */ static MongodExecutable embeddedMongoServer(int port) throws IOException { + IMongodConfig mongodConfig = new MongodConfigBuilder() .version(Version.Main.PRODUCTION) .net(new Net(port, Network.localhostIsIPv6())) .build(); + MongodStarter mongodStarter = MongodStarter.getDefaultInstance(); + return mongodStarter.prepare(mongodConfig); } diff --git a/spring-session/src/integration-test/java/org/springframework/session/data/mongo/MongoRepositoryJacksonITests.java b/src/test/java/org/springframework/session/data/mongo/integration/MongoRepositoryJacksonITest.java similarity index 79% rename from spring-session/src/integration-test/java/org/springframework/session/data/mongo/MongoRepositoryJacksonITests.java rename to src/test/java/org/springframework/session/data/mongo/integration/MongoRepositoryJacksonITest.java index 0f05827..45871d3 100644 --- a/spring-session/src/integration-test/java/org/springframework/session/data/mongo/MongoRepositoryJacksonITests.java +++ b/src/test/java/org/springframework/session/data/mongo/integration/MongoRepositoryJacksonITest.java @@ -13,35 +13,40 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.session.data.mongo; +package org.springframework.session.data.mongo.integration; + +import static org.assertj.core.api.Assertions.*; import java.util.Collections; import java.util.Map; import java.util.UUID; -import com.fasterxml.jackson.databind.Module; import org.junit.Test; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.geo.GeoModule; +import org.springframework.session.data.mongo.AbstractMongoSessionConverter; +import org.springframework.session.data.mongo.JacksonMongoSessionConverter; +import org.springframework.session.data.mongo.MongoExpiringSession; import org.springframework.session.data.mongo.config.annotation.web.http.EnableMongoHttpSession; import org.springframework.test.context.ContextConfiguration; -import static org.assertj.core.api.Assertions.assertThat; +import com.fasterxml.jackson.databind.Module; /** - * Integration tests for {@link MongoOperationsSessionRepository} that use + * Integration tests for {@link org.springframework.session.data.mongo.MongoOperationsSessionRepository} that use * {@link JacksonMongoSessionConverter} based session serialization. * * @author Jakub Kubrynski * @author Vedran Pavic */ @ContextConfiguration -public class MongoRepositoryJacksonITests extends AbstractMongoRepositoryITests { +public class MongoRepositoryJacksonITest extends AbstractMongoRepositoryITest { @Test public void findByCustomIndex() throws Exception { + MongoExpiringSession toSave = this.repository.createSession(); String cartId = "cart-" + UUID.randomUUID(); toSave.setAttribute("cartId", cartId); diff --git a/spring-session/src/integration-test/java/org/springframework/session/data/mongo/MongoRepositoryJdkSerializationITests.java b/src/test/java/org/springframework/session/data/mongo/integration/MongoRepositoryJdkSerializationITest.java similarity index 79% rename from spring-session/src/integration-test/java/org/springframework/session/data/mongo/MongoRepositoryJdkSerializationITests.java rename to src/test/java/org/springframework/session/data/mongo/integration/MongoRepositoryJdkSerializationITest.java index 5c63e09..a2d969f 100644 --- a/spring-session/src/integration-test/java/org/springframework/session/data/mongo/MongoRepositoryJdkSerializationITests.java +++ b/src/test/java/org/springframework/session/data/mongo/integration/MongoRepositoryJdkSerializationITest.java @@ -13,7 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.session.data.mongo; +package org.springframework.session.data.mongo.integration; + +import static org.assertj.core.api.Assertions.*; import java.util.Map; @@ -21,23 +23,25 @@ import org.junit.Test; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.session.data.mongo.AbstractMongoSessionConverter; +import org.springframework.session.data.mongo.JdkMongoSessionConverter; +import org.springframework.session.data.mongo.MongoExpiringSession; import org.springframework.session.data.mongo.config.annotation.web.http.EnableMongoHttpSession; import org.springframework.test.context.ContextConfiguration; -import static org.assertj.core.api.Assertions.assertThat; - /** - * Integration tests for {@link MongoOperationsSessionRepository} that use - * {@link JacksonMongoSessionConverter} based session serialization. + * Integration tests for {@link org.springframework.session.data.mongo.MongoOperationsSessionRepository} that use + * {@link JdkMongoSessionConverter} based session serialization. * * @author Jakub Kubrynski * @author Vedran Pavic */ @ContextConfiguration -public class MongoRepositoryJdkSerializationITests extends AbstractMongoRepositoryITests { +public class MongoRepositoryJdkSerializationITest extends AbstractMongoRepositoryITest { @Test public void findByDeletedSecurityPrincipalNameReload() throws Exception { + MongoExpiringSession toSave = this.repository.createSession(); toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.context); @@ -54,8 +58,8 @@ public class MongoRepositoryJdkSerializationITests extends AbstractMongoReposito } @Test - public void findByPrincipalNameNoSecurityPrincipalNameChangeReload() - throws Exception { + public void findByPrincipalNameNoSecurityPrincipalNameChangeReload() throws Exception { + MongoExpiringSession toSave = this.repository.createSession(); toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.context); diff --git a/spring-session/src/integration-test/java/org/springframework/session/data/SessionEventRegistry.java b/src/test/java/org/springframework/session/data/mongo/integration/SessionEventRegistry.java similarity index 97% rename from spring-session/src/integration-test/java/org/springframework/session/data/SessionEventRegistry.java rename to src/test/java/org/springframework/session/data/mongo/integration/SessionEventRegistry.java index fb742a7..9e98bc7 100644 --- a/spring-session/src/integration-test/java/org/springframework/session/data/SessionEventRegistry.java +++ b/src/test/java/org/springframework/session/data/mongo/integration/SessionEventRegistry.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.session.data; +package org.springframework.session.data.mongo.integration; import java.util.HashMap; import java.util.Map; @@ -23,10 +23,12 @@ import org.springframework.context.ApplicationListener; import org.springframework.session.events.AbstractSessionEvent; public class SessionEventRegistry implements ApplicationListener { + private Map events = new HashMap(); private Map locks = new HashMap(); public void onApplicationEvent(AbstractSessionEvent event) { + String sessionId = event.getSessionId(); this.events.put(sessionId, event); Object lock = getLock(sessionId); @@ -36,6 +38,7 @@ public class SessionEventRegistry implements ApplicationListener E waitForEvent(String sessionId) throws InterruptedException { + Object lock = getLock(sessionId); synchronized (lock) { if (!this.events.containsKey(sessionId)) { @@ -63,6 +67,7 @@ public class SessionEventRegistry implements ApplicationListener