JETTY-1529 Ensure new session that has just been authenticated does not get renewed

This commit is contained in:
Jan Bartel 2012-07-27 15:31:34 +10:00
parent 2de6fa5c35
commit 748f06cad7
8 changed files with 73 additions and 27 deletions

View File

@ -24,8 +24,11 @@ import java.util.Set;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
import org.eclipse.jetty.security.authentication.DeferredAuthentication;
import org.eclipse.jetty.server.AbstractHttpConnection;
import org.eclipse.jetty.server.Authentication;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Request;
@ -34,6 +37,7 @@ import org.eclipse.jetty.server.UserIdentity;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.ContextHandler.Context;
import org.eclipse.jetty.server.handler.HandlerWrapper;
import org.eclipse.jetty.server.session.AbstractSessionManager;
import org.eclipse.jetty.util.component.LifeCycle;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
@ -286,6 +290,32 @@ public abstract class SecurityHandler extends HandlerWrapper implements Authenti
getInitParameter(name)==null)
setInitParameter(name,context.getInitParameter(name));
}
//register a session listener to handle securing sessions when authentication is performed
context.getContextHandler().addEventListener(new HttpSessionListener()
{
public void sessionDestroyed(HttpSessionEvent se)
{
}
public void sessionCreated(HttpSessionEvent se)
{
//if current request is authenticated, then as we have just created the session, mark it as secure, as it has not yet been returned to a user
AbstractHttpConnection connection = AbstractHttpConnection.getCurrentConnection();
if (connection == null)
return;
Request request = connection.getRequest();
if (request == null)
return;
if (request.isSecure())
{
se.getSession().setAttribute(AbstractSessionManager.SESSION_KNOWN_ONLY_TO_AUTHENTICATED, Boolean.TRUE);
}
}
});
}
// complicated resolution of login and identity service to handle

View File

@ -83,7 +83,7 @@ public class BasicAuthenticator extends LoginAuthenticator
UserIdentity user = _loginService.login(username,password);
if (user!=null)
{
renewSessionOnAuthentication(request,response);
renewSession(request,response);
return new UserAuthentication(getAuthMethod(),user);
}
}

View File

@ -119,7 +119,7 @@ public class ClientCertAuthenticator extends LoginAuthenticator
UserIdentity user = _loginService.login(username,credential);
if (user!=null)
{
renewSessionOnAuthentication(request,response);
renewSession(request,response);
return new UserAuthentication(getAuthMethod(),user);
}
}

View File

@ -183,7 +183,7 @@ public class DigestAuthenticator extends LoginAuthenticator
UserIdentity user = _loginService.login(digest.username,digest);
if (user!=null)
{
renewSessionOnAuthentication(request,response);
renewSession(request,response);
return new UserAuthentication(getAuthMethod(),user);
}
}

View File

@ -204,7 +204,7 @@ public class FormAuthenticator extends LoginAuthenticator
UserIdentity user = _loginService.login(username,password);
if (user!=null)
{
session=renewSessionOnAuthentication(request,response);
session=renewSession(request,response);
// Redirect to original request
String nuri;

View File

@ -13,10 +13,6 @@
package org.eclipse.jetty.security.authentication;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@ -24,10 +20,10 @@ import javax.servlet.http.HttpSession;
import org.eclipse.jetty.security.Authenticator;
import org.eclipse.jetty.security.IdentityService;
import org.eclipse.jetty.security.LoginService;
import org.eclipse.jetty.server.session.AbstractSessionManager;
public abstract class LoginAuthenticator implements Authenticator
{
public final static String SESSION_SECURED="org.eclipse.jetty.security.secured";
protected final DeferredAuthentication _deferred=new DeferredAuthentication(this);
protected LoginService _loginService;
protected IdentityService _identityService;
@ -53,34 +49,29 @@ public abstract class LoginAuthenticator implements Authenticator
return _loginService;
}
/* ------------------------------------------------------------ */
/** Change the session when the request is authenticated for the first time
/** Change the session id.
* The session is changed to a new instance with a new ID if and only if:<ul>
* <li>A session exists.
* <li>The {@link AuthConfiguration#isSessionRenewedOnAuthentication()} returns true.
* <li>The session ID has been given to unauthenticated responses
* </ul>
* @param request
* @param response
* @return The new session.
*/
protected HttpSession renewSessionOnAuthentication(HttpServletRequest request, HttpServletResponse response)
protected HttpSession renewSession(HttpServletRequest request, HttpServletResponse response)
{
HttpSession httpSession = request.getSession(false);
if (_renewSession && httpSession!=null && httpSession.getAttribute(SESSION_SECURED)==null)
//if we should renew sessions, and there is an existing session that may have been seen by non-authenticated users
//(indicated by SESSION_SECURED not being set on the session) then we should change id
if (_renewSession && httpSession!=null && httpSession.getAttribute(AbstractSessionManager.SESSION_KNOWN_ONLY_TO_AUTHENTICATED)!=Boolean.TRUE)
{
synchronized (this)
{
Map<String,Object> attributes = new HashMap<String, Object>();
for (Enumeration<String> e=httpSession.getAttributeNames();e.hasMoreElements();)
{
String name=e.nextElement();
attributes.put(name,httpSession.getAttribute(name));
httpSession.removeAttribute(name);
}
httpSession.invalidate();
httpSession = request.getSession(true);
httpSession.setAttribute(SESSION_SECURED,Boolean.TRUE);
for (Map.Entry<String, Object> entry: attributes.entrySet())
httpSession.setAttribute(entry.getKey(),entry.getValue());
httpSession = AbstractSessionManager.renewSession(request, httpSession,true);
}
}
return httpSession;
}
}

View File

@ -29,6 +29,7 @@ import org.eclipse.jetty.security.SecurityHandler;
import org.eclipse.jetty.server.Authentication;
import org.eclipse.jetty.server.UserIdentity;
import org.eclipse.jetty.server.UserIdentity.Scope;
import org.eclipse.jetty.server.session.AbstractSessionManager;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
@ -102,7 +103,7 @@ public class SessionAuthentication implements Authentication.User, Serializable,
if (security!=null)
security.logout(this);
if (_session!=null)
_session.removeAttribute(LoginAuthenticator.SESSION_SECURED);
_session.removeAttribute(AbstractSessionManager.SESSION_KNOWN_ONLY_TO_AUTHENTICATED);
}
@Override

View File

@ -18,6 +18,7 @@ import static java.lang.Math.round;
import java.util.Collections;
import java.util.Enumeration;
import java.util.EventListener;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
@ -57,6 +58,7 @@ import org.eclipse.jetty.util.statistic.SampleStatistic;
public abstract class AbstractSessionManager extends AbstractLifeCycle implements SessionManager
{
final static Logger __log = SessionHandler.LOG;
public final static String SESSION_KNOWN_ONLY_TO_AUTHENTICATED="org.eclipse.jetty.security.sessionKnownOnlytoAuthenticated";
/* ------------------------------------------------------------ */
public final static int __distantFuture=60*60*24*7*52*20;
@ -103,6 +105,28 @@ public abstract class AbstractSessionManager extends AbstractLifeCycle implement
protected final CounterStatistic _sessionsStats = new CounterStatistic();
protected final SampleStatistic _sessionTimeStats = new SampleStatistic();
/* ------------------------------------------------------------ */
public static HttpSession renewSession (HttpServletRequest request, HttpSession httpSession, boolean authenticated)
{
Map<String,Object> attributes = new HashMap<String, Object>();
for (Enumeration<String> e=httpSession.getAttributeNames();e.hasMoreElements();)
{
String name=e.nextElement();
attributes.put(name,httpSession.getAttribute(name));
httpSession.removeAttribute(name);
}
httpSession.invalidate();
httpSession = request.getSession(true);
if (authenticated)
httpSession.setAttribute(SESSION_KNOWN_ONLY_TO_AUTHENTICATED, Boolean.TRUE);
for (Map.Entry<String, Object> entry: attributes.entrySet())
httpSession.setAttribute(entry.getKey(),entry.getValue());
return httpSession;
}
/* ------------------------------------------------------------ */
public AbstractSessionManager()
{