SAML IdMapperUpdaterSessionListener should be added always and must implement HttpSessionIdListener interface
Closes #32084 Signed-off-by: rmartinc <rmartinc@redhat.com>
This commit is contained in:
parent
3ff825807f
commit
a38d3b2f55
4 changed files with 50 additions and 7 deletions
|
@ -24,6 +24,7 @@ import jakarta.servlet.http.HttpSession;
|
||||||
import jakarta.servlet.http.HttpSessionAttributeListener;
|
import jakarta.servlet.http.HttpSessionAttributeListener;
|
||||||
import jakarta.servlet.http.HttpSessionBindingEvent;
|
import jakarta.servlet.http.HttpSessionBindingEvent;
|
||||||
import jakarta.servlet.http.HttpSessionEvent;
|
import jakarta.servlet.http.HttpSessionEvent;
|
||||||
|
import jakarta.servlet.http.HttpSessionIdListener;
|
||||||
import jakarta.servlet.http.HttpSessionListener;
|
import jakarta.servlet.http.HttpSessionListener;
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
|
|
||||||
|
@ -31,7 +32,7 @@ import org.jboss.logging.Logger;
|
||||||
*
|
*
|
||||||
* @author hmlnarik
|
* @author hmlnarik
|
||||||
*/
|
*/
|
||||||
public class IdMapperUpdaterSessionListener implements HttpSessionListener, HttpSessionAttributeListener {
|
public class IdMapperUpdaterSessionListener implements HttpSessionListener, HttpSessionAttributeListener, HttpSessionIdListener {
|
||||||
|
|
||||||
private static final Logger LOG = Logger.getLogger(IdMapperUpdaterSessionListener.class);
|
private static final Logger LOG = Logger.getLogger(IdMapperUpdaterSessionListener.class);
|
||||||
|
|
||||||
|
@ -56,6 +57,15 @@ public class IdMapperUpdaterSessionListener implements HttpSessionListener, Http
|
||||||
unmap(session.getId(), session.getAttribute(SamlSession.class.getName()));
|
unmap(session.getId(), session.getAttribute(SamlSession.class.getName()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sessionIdChanged(HttpSessionEvent hse, String oldSessionId) {
|
||||||
|
LOG.debugf("Session changed ID from %s", oldSessionId);
|
||||||
|
HttpSession session = hse.getSession();
|
||||||
|
Object value = session.getAttribute(SamlSession.class.getName());
|
||||||
|
unmap(oldSessionId, value);
|
||||||
|
map(session.getId(), value);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void attributeAdded(HttpSessionBindingEvent hsbe) {
|
public void attributeAdded(HttpSessionBindingEvent hsbe) {
|
||||||
HttpSession session = hsbe.getSession();
|
HttpSession session = hsbe.getSession();
|
||||||
|
|
|
@ -156,14 +156,14 @@ public class KeycloakConfigurationServletListener implements ServletContextListe
|
||||||
public void addTokenStoreUpdaters(ServletContext servletContext) {
|
public void addTokenStoreUpdaters(ServletContext servletContext) {
|
||||||
SessionIdMapperUpdater updater = this.idMapperUpdater;
|
SessionIdMapperUpdater updater = this.idMapperUpdater;
|
||||||
|
|
||||||
|
servletContext.addListener(new IdMapperUpdaterSessionListener(idMapper)); // This takes care of HTTP sessions manipulated locally
|
||||||
|
|
||||||
try {
|
try {
|
||||||
String idMapperSessionUpdaterClasses = servletContext.getInitParameter("keycloak.sessionIdMapperUpdater.classes");
|
String idMapperSessionUpdaterClasses = servletContext.getInitParameter("keycloak.sessionIdMapperUpdater.classes");
|
||||||
if (idMapperSessionUpdaterClasses == null) {
|
if (idMapperSessionUpdaterClasses == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
servletContext.addListener(new IdMapperUpdaterSessionListener(idMapper)); // This takes care of HTTP sessions manipulated locally
|
|
||||||
|
|
||||||
updater = SessionIdMapperUpdater.DIRECT;
|
updater = SessionIdMapperUpdater.DIRECT;
|
||||||
|
|
||||||
for (String clazz : idMapperSessionUpdaterClasses.split("\\s*,\\s*")) {
|
for (String clazz : idMapperSessionUpdaterClasses.split("\\s*,\\s*")) {
|
||||||
|
|
|
@ -23,7 +23,6 @@ import org.keycloak.adapters.saml.SamlAuthenticationError;
|
||||||
import org.keycloak.adapters.saml.SamlPrincipal;
|
import org.keycloak.adapters.saml.SamlPrincipal;
|
||||||
import org.keycloak.adapters.saml.SamlSession;
|
import org.keycloak.adapters.saml.SamlSession;
|
||||||
import org.keycloak.adapters.spi.AuthenticationError;
|
import org.keycloak.adapters.spi.AuthenticationError;
|
||||||
import org.keycloak.saml.processing.core.saml.v2.constants.X500SAMLProfileConstants;
|
|
||||||
|
|
||||||
import jakarta.servlet.RequestDispatcher;
|
import jakarta.servlet.RequestDispatcher;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
@ -45,8 +44,6 @@ import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import javax.xml.parsers.DocumentBuilderFactory;
|
|
||||||
import javax.xml.transform.OutputKeys;
|
|
||||||
import javax.xml.transform.Transformer;
|
import javax.xml.transform.Transformer;
|
||||||
import javax.xml.transform.TransformerException;
|
import javax.xml.transform.TransformerException;
|
||||||
import javax.xml.transform.TransformerFactory;
|
import javax.xml.transform.TransformerFactory;
|
||||||
|
@ -104,11 +101,19 @@ public class SendUsernameServlet {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Path("change-session-id")
|
||||||
|
public Response changeSessionId() throws IOException {
|
||||||
|
System.out.println("In SendUsername Servlet changeSessionId()");
|
||||||
|
final String sessionId = httpServletRequest.changeSessionId();
|
||||||
|
|
||||||
|
return Response.ok(sessionId).header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN_TYPE + ";charset=UTF-8").build();
|
||||||
|
}
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
@Path("getAssertionFromDocument")
|
@Path("getAssertionFromDocument")
|
||||||
public Response getAssertionFromDocument() throws IOException, TransformerException {
|
public Response getAssertionFromDocument() throws IOException, TransformerException {
|
||||||
sentPrincipal = httpServletRequest.getUserPrincipal();
|
sentPrincipal = httpServletRequest.getUserPrincipal();
|
||||||
DocumentBuilderFactory domFact = DocumentBuilderFactory.newInstance();
|
|
||||||
Document doc = ((SamlPrincipal) sentPrincipal).getAssertionDocument();
|
Document doc = ((SamlPrincipal) sentPrincipal).getAssertionDocument();
|
||||||
String xml = "";
|
String xml = "";
|
||||||
if (doc != null) {
|
if (doc != null) {
|
||||||
|
|
|
@ -1987,6 +1987,34 @@ public class SAMLServletAdapterTest extends AbstractSAMLServletAdapterTest {
|
||||||
checkLoggedOut(salesPostSigEmailServletPage, testRealmSAMLPostLoginPage);
|
checkLoggedOut(salesPostSigEmailServletPage, testRealmSAMLPostLoginPage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testChangeSessionID() throws Exception {
|
||||||
|
// login in the employeeDom application
|
||||||
|
assertSuccessfulLogin(employeeDomServletPage, bburkeUser, testRealmSAMLPostLoginPage, "principal=bburke");
|
||||||
|
assertSuccessfullyLoggedIn(employeeDomServletPage, "principal=bburke");
|
||||||
|
String sessionId = driver.manage().getCookieNamed("JSESSIONID").getValue();
|
||||||
|
|
||||||
|
// retrieve the saml document
|
||||||
|
driver.navigate().to(employeeDomServletPage.getUriBuilder().clone().path("getAssertionFromDocument").build().toURL());
|
||||||
|
waitForPageToLoad();
|
||||||
|
String xml = getRawPageSource();
|
||||||
|
Assert.assertNotEquals("", xml);
|
||||||
|
|
||||||
|
// change the session id
|
||||||
|
driver.navigate().to(employeeDomServletPage.getUriBuilder().clone().path("change-session-id").build().toURL());
|
||||||
|
waitForPageToLoad();
|
||||||
|
Assert.assertNotEquals("SessionID has not been changed at login", sessionId, driver.manage().getCookieNamed("JSESSIONID").getValue());
|
||||||
|
|
||||||
|
// retrieve again the saml document and should be the same as login should be maintained
|
||||||
|
driver.navigate().to(employeeDomServletPage.getUriBuilder().clone().path("getAssertionFromDocument").build().toURL());
|
||||||
|
waitForPageToLoad();
|
||||||
|
Assert.assertEquals(xml, getRawPageSource());
|
||||||
|
|
||||||
|
// logout
|
||||||
|
employeeDomServletPage.logout();
|
||||||
|
checkLoggedOut(employeeDomServletPage, testRealmSAMLPostLoginPage);
|
||||||
|
}
|
||||||
|
|
||||||
public static void printDocument(Source doc, OutputStream out) throws IOException, TransformerException {
|
public static void printDocument(Source doc, OutputStream out) throws IOException, TransformerException {
|
||||||
TransformerFactory tf = TransformerFactory.newInstance();
|
TransformerFactory tf = TransformerFactory.newInstance();
|
||||||
Transformer transformer = tf.newTransformer();
|
Transformer transformer = tf.newTransformer();
|
||||||
|
|
Loading…
Reference in a new issue