From 5fc6414377aea64953c2ecf57bb7101d052fa772 Mon Sep 17 00:00:00 2001 From: Venkata Jaswanth Date: Thu, 14 Jun 2018 01:36:07 +1000 Subject: [PATCH] SessionRegistryImpl is now aware of SessionIdChangedEvent --- .../core/session/SessionIdChangedEvent.java | 29 +++++++++++ .../core/session/SessionRegistryImpl.java | 18 +++++-- .../session/SessionRegistryImplTests.java | 27 +++++++++++ .../session/HttpSessionEventPublisher.java | 15 +++++- .../session/HttpSessionIdChangedEvent.java | 48 +++++++++++++++++++ .../HttpSessionEventPublisherTests.java | 20 ++++++++ .../web/session/MockApplicationListener.java | 12 +++++ 7 files changed, 164 insertions(+), 5 deletions(-) create mode 100644 core/src/main/java/org/springframework/security/core/session/SessionIdChangedEvent.java create mode 100644 web/src/main/java/org/springframework/security/web/session/HttpSessionIdChangedEvent.java diff --git a/core/src/main/java/org/springframework/security/core/session/SessionIdChangedEvent.java b/core/src/main/java/org/springframework/security/core/session/SessionIdChangedEvent.java new file mode 100644 index 0000000000..8cefdeb348 --- /dev/null +++ b/core/src/main/java/org/springframework/security/core/session/SessionIdChangedEvent.java @@ -0,0 +1,29 @@ +/* + * Copyright 2002-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.security.core.session; + +import org.springframework.context.ApplicationEvent; + +public abstract class SessionIdChangedEvent extends ApplicationEvent { + + public SessionIdChangedEvent(Object source) { + super(source); + } + + public abstract String getOldSessionId(); + + public abstract String getNewSessionId(); +} diff --git a/core/src/main/java/org/springframework/security/core/session/SessionRegistryImpl.java b/core/src/main/java/org/springframework/security/core/session/SessionRegistryImpl.java index bd3f137d2b..041009cef7 100644 --- a/core/src/main/java/org/springframework/security/core/session/SessionRegistryImpl.java +++ b/core/src/main/java/org/springframework/security/core/session/SessionRegistryImpl.java @@ -18,6 +18,7 @@ package org.springframework.security.core.session; 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.util.Assert; @@ -40,7 +41,7 @@ import java.util.concurrent.CopyOnWriteArraySet; * @author Luke Taylor */ public class SessionRegistryImpl implements SessionRegistry, - ApplicationListener { + ApplicationListener { // ~ Instance fields // ================================================================================================ @@ -101,9 +102,18 @@ public class SessionRegistryImpl implements SessionRegistry, return sessionIds.get(sessionId); } - public void onApplicationEvent(SessionDestroyedEvent event) { - String sessionId = event.getId(); - removeSessionInformation(sessionId); + public void onApplicationEvent(ApplicationEvent event) { + if (event instanceof SessionDestroyedEvent) { + SessionDestroyedEvent sessionDestroyedEvent = (SessionDestroyedEvent) event; + String sessionId = sessionDestroyedEvent.getId(); + removeSessionInformation(sessionId); + } else if (event instanceof SessionIdChangedEvent) { + SessionIdChangedEvent sessionIdChangedEvent = (SessionIdChangedEvent) event; + String oldSessionId = sessionIdChangedEvent.getOldSessionId(); + Object principal = sessionIds.get(oldSessionId).getPrincipal(); + removeSessionInformation(oldSessionId); + registerNewSession(sessionIdChangedEvent.getNewSessionId(), principal); + } } public void refreshLastRequest(String sessionId) { diff --git a/core/src/test/java/org/springframework/security/core/session/SessionRegistryImplTests.java b/core/src/test/java/org/springframework/security/core/session/SessionRegistryImplTests.java index 95ec0062e0..7ed19b2bc6 100644 --- a/core/src/test/java/org/springframework/security/core/session/SessionRegistryImplTests.java +++ b/core/src/test/java/org/springframework/security/core/session/SessionRegistryImplTests.java @@ -69,6 +69,33 @@ public class SessionRegistryImplTests { assertThat(sessionRegistry.getSessionInformation(sessionId)).isNull(); } + @Test + public void sessionIdChangedEventRemovesOldSessionAndAddsANewSession() { + Object principal = "Some principal object"; + final String sessionId = "zzzz"; + final String newSessionId = "123"; + + // Register new Session + sessionRegistry.registerNewSession(sessionId, principal); + + // De-register session via an ApplicationEvent + sessionRegistry.onApplicationEvent(new SessionIdChangedEvent("") { + @Override + public String getOldSessionId() { + return sessionId; + } + + @Override + public String getNewSessionId() { + return newSessionId; + } + }); + + assertThat(sessionRegistry.getSessionInformation(sessionId)).isNull(); + assertThat(sessionRegistry.getSessionInformation(newSessionId)).isNotNull(); + assertThat(sessionRegistry.getSessionInformation(newSessionId).getPrincipal()).isEqualTo(principal); + } + @Test public void testMultiplePrincipals() { Object principal1 = "principal_1"; diff --git a/web/src/main/java/org/springframework/security/web/session/HttpSessionEventPublisher.java b/web/src/main/java/org/springframework/security/web/session/HttpSessionEventPublisher.java index d45ad2acdf..babbf1a231 100644 --- a/web/src/main/java/org/springframework/security/web/session/HttpSessionEventPublisher.java +++ b/web/src/main/java/org/springframework/security/web/session/HttpSessionEventPublisher.java @@ -25,6 +25,7 @@ import org.springframework.security.web.context.support.SecurityWebApplicationCo import javax.servlet.ServletContext; import javax.servlet.http.HttpSessionEvent; +import javax.servlet.http.HttpSessionIdListener; import javax.servlet.http.HttpSessionListener; /** @@ -44,7 +45,7 @@ import javax.servlet.http.HttpSessionListener; * * @author Ray Krueger */ -public class HttpSessionEventPublisher implements HttpSessionListener { +public class HttpSessionEventPublisher implements HttpSessionListener, HttpSessionIdListener { // ~ Static fields/initializers // ===================================================================================== @@ -90,4 +91,16 @@ public class HttpSessionEventPublisher implements HttpSessionListener { getContext(event.getSession().getServletContext()).publishEvent(e); } + + @Override + public void sessionIdChanged(HttpSessionEvent event, String oldSessionId) { + HttpSessionIdChangedEvent e = new HttpSessionIdChangedEvent(event.getSession(), oldSessionId); + Log log = LogFactory.getLog(LOGGER_NAME); + + if (log.isDebugEnabled()) { + log.debug("Publishing event: " + e); + } + + getContext(event.getSession().getServletContext()).publishEvent(e); + } } diff --git a/web/src/main/java/org/springframework/security/web/session/HttpSessionIdChangedEvent.java b/web/src/main/java/org/springframework/security/web/session/HttpSessionIdChangedEvent.java new file mode 100644 index 0000000000..9c824eafa4 --- /dev/null +++ b/web/src/main/java/org/springframework/security/web/session/HttpSessionIdChangedEvent.java @@ -0,0 +1,48 @@ +/* + * Copyright 2004, 2005, 2006 Acegi Technology Pty Limited + * + * 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.security.web.session; + +import javax.servlet.http.HttpSession; + +import org.springframework.security.core.session.SessionIdChangedEvent; + +/** + * Published by the {@link HttpSessionEventPublisher} when an {@code HttpSession} id + * is changed + * + */ +public class HttpSessionIdChangedEvent extends SessionIdChangedEvent { + private final String oldSessionId; + private final String newSessionid; + // ~ Constructors + // =================================================================================================== + + public HttpSessionIdChangedEvent(HttpSession session, String oldSessionId) { + super(session); + this.oldSessionId = oldSessionId; + this.newSessionid = session.getId(); + } + + public String getOldSessionId() { + return oldSessionId; + } + + @Override + public String getNewSessionId() { + return newSessionid; + } +} diff --git a/web/src/test/java/org/springframework/security/web/session/HttpSessionEventPublisherTests.java b/web/src/test/java/org/springframework/security/web/session/HttpSessionEventPublisherTests.java index def6f4b5f6..6c7f6abe5d 100644 --- a/web/src/test/java/org/springframework/security/web/session/HttpSessionEventPublisherTests.java +++ b/web/src/test/java/org/springframework/security/web/session/HttpSessionEventPublisherTests.java @@ -72,6 +72,11 @@ public class HttpSessionEventPublisherTests { assertThat(listener.getDestroyedEvent()).isNotNull(); assertThat(listener.getCreatedEvent()).isNull(); assertThat(listener.getDestroyedEvent().getSession()).isEqualTo(session); + + publisher.sessionIdChanged(event, "oldSessionId"); + assertThat(listener.getSessionIdChangedEvent()).isNotNull(); + assertThat(listener.getSessionIdChangedEvent().getOldSessionId()).isEqualTo("oldSessionId"); + listener.setSessionIdChangedEvent(null); } @Test @@ -108,6 +113,11 @@ public class HttpSessionEventPublisherTests { assertThat(listener.getDestroyedEvent()).isNotNull(); assertThat(listener.getCreatedEvent()).isNull(); assertThat(listener.getDestroyedEvent().getSession()).isEqualTo(session); + + publisher.sessionIdChanged(event, "oldSessionId"); + assertThat(listener.getSessionIdChangedEvent()).isNotNull(); + assertThat(listener.getSessionIdChangedEvent().getOldSessionId()).isEqualTo("oldSessionId"); + listener.setSessionIdChangedEvent(null); } // SEC-2599 @@ -131,4 +141,14 @@ public class HttpSessionEventPublisherTests { publisher.sessionDestroyed(event); } + + @Test(expected = IllegalStateException.class) + public void sessionIdChangeNullApplicationContext() { + HttpSessionEventPublisher publisher = new HttpSessionEventPublisher(); + MockServletContext servletContext = new MockServletContext(); + MockHttpSession session = new MockHttpSession(servletContext); + HttpSessionEvent event = new HttpSessionEvent(session); + + publisher.sessionIdChanged(event, "oldSessionId"); + } } diff --git a/web/src/test/java/org/springframework/security/web/session/MockApplicationListener.java b/web/src/test/java/org/springframework/security/web/session/MockApplicationListener.java index 81a95c2826..8035a67dde 100644 --- a/web/src/test/java/org/springframework/security/web/session/MockApplicationListener.java +++ b/web/src/test/java/org/springframework/security/web/session/MockApplicationListener.java @@ -32,6 +32,7 @@ public class MockApplicationListener implements ApplicationListener