Merge remote-tracking branch 'origin/jetty-10.0.x' into jetty-11.0.x
This commit is contained in:
commit
9d96b4fc74
|
@ -3,7 +3,7 @@
|
|||
<!-- =============================================================== -->
|
||||
<!-- Configure the test-jndi webapp -->
|
||||
<!-- =============================================================== -->
|
||||
<Configure id='wac' class="org.eclipse.jetty.webapp.WebAppContext">
|
||||
<Configure id="wac" class="org.eclipse.jetty.webapp.WebAppContext">
|
||||
|
||||
<New id="tx" class="org.eclipse.jetty.plus.jndi.Transaction">
|
||||
<Arg>
|
||||
|
@ -21,7 +21,7 @@
|
|||
<!-- Define an env entry with Server scope for java:comp/env -->
|
||||
<New id="woggle" class="org.eclipse.jetty.plus.jndi.EnvEntry">
|
||||
<Arg>
|
||||
<Property name='server' />
|
||||
<Ref refid="Server" />
|
||||
</Arg>
|
||||
<Arg>woggle</Arg>
|
||||
<Arg type="java.lang.Integer">4000</Arg>
|
||||
|
@ -31,7 +31,7 @@
|
|||
<!-- Define an env entry with webapp scope for java:comp/env -->
|
||||
<New id="wiggle" class="org.eclipse.jetty.plus.jndi.EnvEntry">
|
||||
<Arg>
|
||||
<Ref refid='wac' />
|
||||
<Ref refid="wac" />
|
||||
</Arg>
|
||||
<Arg>wiggle</Arg>
|
||||
<Arg type="java.lang.Double">100</Arg>
|
||||
|
@ -41,7 +41,7 @@
|
|||
<!-- Mail Session setup -->
|
||||
<New id="xxxmail" class="org.eclipse.jetty.plus.jndi.Resource">
|
||||
<Arg>
|
||||
<Ref refid='wac' />
|
||||
<Ref refid="wac" />
|
||||
</Arg>
|
||||
<Arg>mail/Session</Arg>
|
||||
<Arg>
|
||||
|
@ -63,7 +63,7 @@
|
|||
<!-- A mock DataSource -->
|
||||
<New id="mydatasource" class="org.eclipse.jetty.plus.jndi.Resource">
|
||||
<Arg>
|
||||
<Ref refid='wac' />
|
||||
<Ref refid="wac" />
|
||||
</Arg>
|
||||
<Arg>jdbc/mydatasource</Arg>
|
||||
<Arg>
|
||||
|
|
|
@ -16,9 +16,6 @@ etc/jetty-deploy.xml
|
|||
[ini-template]
|
||||
# Monitored directory name (relative to $jetty.base)
|
||||
# jetty.deploy.monitoredDir=webapps
|
||||
# - OR -
|
||||
# Monitored directory path (fully qualified)
|
||||
# jetty.deploy.monitoredPath=/var/www/webapps
|
||||
|
||||
# Defaults Descriptor for all deployed webapps
|
||||
# jetty.deploy.defaultsDescriptorPath=${jetty.base}/etc/webdefault.xml
|
||||
|
|
|
@ -37,4 +37,4 @@ jetty.session.hazelcast.hazelcastInstanceName=JETTY_DISTRIBUTED_SESSION_INSTANCE
|
|||
jetty.session.hazelcast.useQueries=false
|
||||
jetty.session.gracePeriod.seconds=3600
|
||||
jetty.session.savePeriod.seconds=0
|
||||
#jetty.session.hazelcast.configurationLocation
|
||||
#jetty.session.hazelcast.configurationLocation=
|
||||
|
|
|
@ -38,5 +38,5 @@ jetty.session.hazelcast.onlyClient=true
|
|||
jetty.session.hazelcast.useQueries=false
|
||||
jetty.session.gracePeriod.seconds=3600
|
||||
jetty.session.savePeriod.seconds=0
|
||||
#jetty.session.hazelcast.configurationLocation
|
||||
#jetty.session.hazelcast.configurationLocation=
|
||||
#jetty.session.hazelcast.addresses=
|
||||
|
|
|
@ -117,7 +117,21 @@ public interface Authenticator
|
|||
|
||||
IdentityService getIdentityService();
|
||||
|
||||
/**
|
||||
* Should session ID be renewed on authentication.
|
||||
* @return true if the session ID should be renewed on authentication
|
||||
*/
|
||||
boolean isSessionRenewedOnAuthentication();
|
||||
|
||||
/**
|
||||
* Get the interval in seconds, which if non-zero, will be set
|
||||
* with {@link jakarta.servlet.http.HttpSession#setMaxInactiveInterval(int)}
|
||||
* when a session is newly authenticated
|
||||
* @return An interval in seconds; or 0 to not set the interval
|
||||
* on authentication; or a negative number to make the
|
||||
* session never timeout after authentication.
|
||||
*/
|
||||
int getSessionMaxInactiveIntervalOnAuthentication();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -68,7 +68,8 @@ public abstract class SecurityHandler extends HandlerWrapper implements Authenti
|
|||
private final Map<String, String> _initParameters = new HashMap<>();
|
||||
private LoginService _loginService;
|
||||
private IdentityService _identityService;
|
||||
private boolean _renewSession = true;
|
||||
private boolean _renewSessionOnAuthentication = true;
|
||||
private int _sessionMaxInactiveIntervalOnAuthentication = 0;
|
||||
|
||||
static
|
||||
{
|
||||
|
@ -433,7 +434,7 @@ public abstract class SecurityHandler extends HandlerWrapper implements Authenti
|
|||
@Override
|
||||
public boolean isSessionRenewedOnAuthentication()
|
||||
{
|
||||
return _renewSession;
|
||||
return _renewSessionOnAuthentication;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -446,7 +447,26 @@ public abstract class SecurityHandler extends HandlerWrapper implements Authenti
|
|||
*/
|
||||
public void setSessionRenewedOnAuthentication(boolean renew)
|
||||
{
|
||||
_renewSession = renew;
|
||||
_renewSessionOnAuthentication = renew;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSessionMaxInactiveIntervalOnAuthentication()
|
||||
{
|
||||
return _sessionMaxInactiveIntervalOnAuthentication;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the interval in seconds, which if non-zero, will be set with
|
||||
* {@link jakarta.servlet.http.HttpSession#setMaxInactiveInterval(int)}
|
||||
* when a session is newly authenticated.
|
||||
* @param seconds An interval in seconds; or 0 to not set the interval
|
||||
* on authentication; or a negative number to make the
|
||||
* session never timeout after authentication.
|
||||
*/
|
||||
public void setSessionMaxInactiveIntervalOnAuthentication(int seconds)
|
||||
{
|
||||
_sessionMaxInactiveIntervalOnAuthentication = seconds;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -71,4 +71,10 @@ public class WrappedAuthConfiguration implements AuthConfiguration
|
|||
{
|
||||
return _configuration.isSessionRenewedOnAuthentication();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSessionMaxInactiveIntervalOnAuthentication()
|
||||
{
|
||||
return _configuration.getSessionMaxInactiveIntervalOnAuthentication();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,7 +33,8 @@ public abstract class LoginAuthenticator implements Authenticator
|
|||
|
||||
protected LoginService _loginService;
|
||||
protected IdentityService _identityService;
|
||||
private boolean _renewSession;
|
||||
private boolean _sessionRenewedOnAuthentication;
|
||||
private int _sessionMaxInactiveIntervalOnAuthentication;
|
||||
|
||||
protected LoginAuthenticator()
|
||||
{
|
||||
|
@ -87,7 +88,8 @@ public abstract class LoginAuthenticator implements Authenticator
|
|||
_identityService = configuration.getIdentityService();
|
||||
if (_identityService == null)
|
||||
throw new IllegalStateException("No IdentityService for " + this + " in " + configuration);
|
||||
_renewSession = configuration.isSessionRenewedOnAuthentication();
|
||||
_sessionRenewedOnAuthentication = configuration.isSessionRenewedOnAuthentication();
|
||||
_sessionMaxInactiveIntervalOnAuthentication = configuration.getSessionMaxInactiveIntervalOnAuthentication();
|
||||
}
|
||||
|
||||
public LoginService getLoginService()
|
||||
|
@ -109,35 +111,41 @@ public abstract class LoginAuthenticator implements Authenticator
|
|||
*/
|
||||
protected HttpSession renewSession(HttpServletRequest request, HttpServletResponse response)
|
||||
{
|
||||
HttpSession httpSession = request.getSession(false);
|
||||
HttpSession session = request.getSession(false);
|
||||
|
||||
if (_renewSession && httpSession != null)
|
||||
if (session != null && (_sessionRenewedOnAuthentication || _sessionMaxInactiveIntervalOnAuthentication != 0))
|
||||
{
|
||||
synchronized (httpSession)
|
||||
synchronized (session)
|
||||
{
|
||||
//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 (httpSession.getAttribute(Session.SESSION_CREATED_SECURE) != Boolean.TRUE)
|
||||
if (_sessionMaxInactiveIntervalOnAuthentication != 0)
|
||||
session.setMaxInactiveInterval(_sessionMaxInactiveIntervalOnAuthentication < 0 ? -1 : _sessionMaxInactiveIntervalOnAuthentication);
|
||||
if (_sessionRenewedOnAuthentication)
|
||||
{
|
||||
if (httpSession instanceof Session)
|
||||
//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 (session.getAttribute(Session.SESSION_CREATED_SECURE) != Boolean.TRUE)
|
||||
{
|
||||
Session s = (Session)httpSession;
|
||||
String oldId = s.getId();
|
||||
s.renewId(request);
|
||||
s.setAttribute(Session.SESSION_CREATED_SECURE, Boolean.TRUE);
|
||||
if (s.isIdChanged() && (response instanceof Response))
|
||||
((Response)response).replaceCookie(s.getSessionHandler().getSessionCookie(s, request.getContextPath(), request.isSecure()));
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("renew {}->{}", oldId, s.getId());
|
||||
if (session instanceof Session)
|
||||
{
|
||||
Session s = (Session)session;
|
||||
String oldId = s.getId();
|
||||
s.renewId(request);
|
||||
s.setAttribute(Session.SESSION_CREATED_SECURE, Boolean.TRUE);
|
||||
if (s.isIdChanged() && (response instanceof Response))
|
||||
((Response)response).replaceCookie(s.getSessionHandler().getSessionCookie(s, request.getContextPath(), request.isSecure()));
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("renew {}->{}", oldId, s.getId());
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG.warn("Unable to renew session {}", session);
|
||||
}
|
||||
return session;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG.warn("Unable to renew session {}", httpSession);
|
||||
}
|
||||
return httpSession;
|
||||
}
|
||||
}
|
||||
}
|
||||
return httpSession;
|
||||
|
||||
return session;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,6 +55,7 @@ import org.eclipse.jetty.server.UserIdentity;
|
|||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.server.handler.HandlerWrapper;
|
||||
import org.eclipse.jetty.server.session.Session;
|
||||
import org.eclipse.jetty.server.session.SessionHandler;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.TypeUtil;
|
||||
|
@ -80,6 +81,7 @@ import static org.hamcrest.Matchers.startsWith;
|
|||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class ConstraintTest
|
||||
|
@ -89,6 +91,8 @@ public class ConstraintTest
|
|||
private LocalConnector _connector;
|
||||
private ConstraintSecurityHandler _security;
|
||||
private HttpConfiguration _config;
|
||||
private ContextHandler _contextHandler;
|
||||
private SessionHandler _sessionhandler;
|
||||
private Constraint _forbidConstraint;
|
||||
private Constraint _authAnyRoleConstraint;
|
||||
private Constraint _authAdminConstraint;
|
||||
|
@ -106,8 +110,8 @@ public class ConstraintTest
|
|||
_config = _connector.getConnectionFactory(HttpConnectionFactory.class).getHttpConfiguration();
|
||||
_server.setConnectors(new Connector[]{_connector});
|
||||
|
||||
ContextHandler contextHandler = new ContextHandler();
|
||||
SessionHandler sessionHandler = new SessionHandler();
|
||||
_contextHandler = new ContextHandler();
|
||||
_sessionhandler = new SessionHandler();
|
||||
|
||||
TestLoginService loginService = new TestLoginService(TEST_REALM);
|
||||
|
||||
|
@ -118,14 +122,14 @@ public class ConstraintTest
|
|||
loginService.putUser("user3", new Password("password"), new String[]{"foo"});
|
||||
loginService.putUser("user4", new Password("password"), new String[]{"A", "B", "C", "D"});
|
||||
|
||||
contextHandler.setContextPath("/ctx");
|
||||
_server.setHandler(contextHandler);
|
||||
contextHandler.setHandler(sessionHandler);
|
||||
_contextHandler.setContextPath("/ctx");
|
||||
_server.setHandler(_contextHandler);
|
||||
_contextHandler.setHandler(_sessionhandler);
|
||||
|
||||
_server.addBean(loginService);
|
||||
|
||||
_security = new ConstraintSecurityHandler();
|
||||
sessionHandler.setHandler(_security);
|
||||
_sessionhandler.setHandler(_security);
|
||||
RequestHandler requestHandler = new RequestHandler(new String[]{"user", "user4"}, new String[]{"user", "foo"});
|
||||
_security.setHandler(requestHandler);
|
||||
|
||||
|
@ -1189,6 +1193,93 @@ public class ConstraintTest
|
|||
assertThat(response, not(containsString("JSESSIONID=" + session)));
|
||||
}
|
||||
|
||||
public static Stream<Arguments> onAuthenticationTests()
|
||||
{
|
||||
return Stream.of(
|
||||
Arguments.of(false, 0),
|
||||
Arguments.of(false, -1),
|
||||
Arguments.of(false, 2400),
|
||||
Arguments.of(true, 0),
|
||||
Arguments.of(true, -1),
|
||||
Arguments.of(true, 2400)
|
||||
);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("onAuthenticationTests")
|
||||
public void testSessionOnAuthentication(boolean sessionRenewOnAuthentication, int sessionMaxInactiveIntervalOnAuthentication) throws Exception
|
||||
{
|
||||
final int UNAUTH_SECONDS = 1200;
|
||||
|
||||
// Use a FormAuthenticator as an example of session authentication
|
||||
_security.setAuthenticator(new FormAuthenticator("/testLoginPage", "/testErrorPage", false));
|
||||
|
||||
_sessionhandler.setMaxInactiveInterval(UNAUTH_SECONDS);
|
||||
_security.setSessionRenewedOnAuthentication(sessionRenewOnAuthentication);
|
||||
_security.setSessionMaxInactiveIntervalOnAuthentication(sessionMaxInactiveIntervalOnAuthentication);
|
||||
_server.start();
|
||||
|
||||
String response;
|
||||
|
||||
response = _connector.getResponse("GET /ctx/auth/info HTTP/1.0\r\n\r\n");
|
||||
assertThat(response, containsString(" 302 Found"));
|
||||
assertThat(response, containsString("/ctx/testLoginPage"));
|
||||
assertThat(response, containsString("JSESSIONID="));
|
||||
String sessionId = response.substring(response.indexOf("JSESSIONID=") + 11, response.indexOf("; Path=/ctx"));
|
||||
|
||||
response = _connector.getResponse("GET /ctx/testLoginPage HTTP/1.0\r\n" +
|
||||
"Cookie: JSESSIONID=" + sessionId + "\r\n" +
|
||||
"\r\n");
|
||||
assertThat(response, containsString(" 200 OK"));
|
||||
assertThat(response, containsString("URI=/ctx/testLoginPage"));
|
||||
assertThat(response, not(containsString("JSESSIONID=" + sessionId)));
|
||||
|
||||
response = _connector.getResponse("POST /ctx/j_security_check HTTP/1.0\r\n" +
|
||||
"Cookie: JSESSIONID=" + sessionId + "\r\n" +
|
||||
"Content-Type: application/x-www-form-urlencoded\r\n" +
|
||||
"Content-Length: 35\r\n" +
|
||||
"\r\n" +
|
||||
"j_username=user&j_password=password");
|
||||
assertThat(response, startsWith("HTTP/1.1 302 "));
|
||||
assertThat(response, containsString("Location"));
|
||||
assertThat(response, containsString("/ctx/auth/info"));
|
||||
|
||||
if (sessionRenewOnAuthentication)
|
||||
{
|
||||
// check session ID has changed.
|
||||
assertNull(_sessionhandler.getSession(sessionId));
|
||||
assertThat(response, containsString("Set-Cookie:"));
|
||||
assertThat(response, containsString("JSESSIONID="));
|
||||
assertThat(response, not(containsString("JSESSIONID=" + sessionId)));
|
||||
sessionId = response.substring(response.indexOf("JSESSIONID=") + 11, response.indexOf("; Path=/ctx"));
|
||||
}
|
||||
else
|
||||
{
|
||||
// check session ID has not changed.
|
||||
assertThat(response, not(containsString("Set-Cookie:")));
|
||||
assertThat(response, not(containsString("JSESSIONID=")));
|
||||
}
|
||||
|
||||
if (sessionMaxInactiveIntervalOnAuthentication == 0)
|
||||
{
|
||||
// check max interval has not been updated
|
||||
Session session = _sessionhandler.getSession(_sessionhandler.getSessionIdManager().getId(sessionId));
|
||||
assertThat(session.getMaxInactiveInterval(), is(UNAUTH_SECONDS));
|
||||
}
|
||||
else
|
||||
{
|
||||
// check max interval has not been updated
|
||||
Session session = _sessionhandler.getSession(_sessionhandler.getSessionIdManager().getId(sessionId));
|
||||
assertThat(session.getMaxInactiveInterval(), is(sessionMaxInactiveIntervalOnAuthentication));
|
||||
}
|
||||
|
||||
// check session still there.
|
||||
response = _connector.getResponse("GET /ctx/auth/info HTTP/1.0\r\n" +
|
||||
"Cookie: JSESSIONID=" + sessionId + "\r\n" +
|
||||
"\r\n");
|
||||
assertThat(response, startsWith("HTTP/1.1 200 OK"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFormPostRedirect() throws Exception
|
||||
{
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
<New id="DebugListener" class="org.eclipse.jetty.server.DebugListener">
|
||||
<Arg name="outputStream">
|
||||
<New class="org.eclipse.jetty.util.RolloverFileOutputStream">
|
||||
<Arg type="String"><Property name="jetty.logs" default="./logs"/>/yyyy_mm_dd.debug.log</Arg>
|
||||
<Arg type="String"><Property name="jetty.debug.logs" deprecated="jetty.logs" default="./logs"/>/yyyy_mm_dd.debug.log</Arg>
|
||||
<Arg type="boolean"><Property name="jetty.debug.append" default="true"/></Arg>
|
||||
<Arg type="int"><Property name="jetty.debug.retainDays" default="14"/></Arg>
|
||||
<Arg>
|
||||
|
|
|
@ -43,9 +43,6 @@
|
|||
<Set name="acceptedTcpNoDelay"><Property name="jetty.http.acceptedTcpNoDelay" default="true"/></Set>
|
||||
<Set name="acceptedReceiveBufferSize" property="jetty.http.acceptedReceiveBufferSize" />
|
||||
<Set name="acceptedSendBufferSize" property="jetty.http.acceptedSendBufferSize" />
|
||||
<Get name="SelectorManager">
|
||||
<Set name="connectTimeout"><Property name="jetty.http.connectTimeout" default="15000"/></Set>
|
||||
</Get>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
|
|
|
@ -36,9 +36,6 @@
|
|||
<Set name="acceptedTcpNoDelay"><Property name="jetty.ssl.acceptedTcpNoDelay" default="true"/></Set>
|
||||
<Set name="acceptedReceiveBufferSize" property="jetty.ssl.acceptedReceiveBufferSize" />
|
||||
<Set name="acceptedSendBufferSize" property="jetty.ssl.acceptedSendBufferSize" />
|
||||
<Get name="SelectorManager">
|
||||
<Set name="connectTimeout" property="jetty.ssl.connectTimeout"/>
|
||||
</Get>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
|
|
|
@ -23,6 +23,12 @@ etc/jetty-debug.xml
|
|||
## How many days to retain old log files
|
||||
# jetty.debug.retainDays=14
|
||||
|
||||
## Should existing log be appended to
|
||||
# jetty.debug.append=true
|
||||
|
||||
## Log directory for jetty debug logs
|
||||
# jetty.debug.logs=./logs
|
||||
|
||||
## Timezone of the log entries
|
||||
# jetty.debug.timezone=GMT
|
||||
|
||||
|
|
|
@ -18,9 +18,6 @@ etc/jetty-gzip.xml
|
|||
## Minimum content length after which gzip is enabled
|
||||
# jetty.gzip.minGzipSize=32
|
||||
|
||||
## Check whether a file with *.gz extension exists
|
||||
# jetty.gzip.checkGzExists=false
|
||||
|
||||
## Inflate request buffer size, or 0 for no request inflation
|
||||
# jetty.gzip.inflateBufferSize=0
|
||||
|
||||
|
|
|
@ -39,6 +39,9 @@ etc/jetty.xml
|
|||
## Max response content write length that is buffered (in bytes)
|
||||
# jetty.httpConfig.outputAggregationSize=8192
|
||||
|
||||
## If HTTP/1.x persistent connections should be enabled
|
||||
# jetty.httpConfig.persistentConnectionsEnabled=true
|
||||
|
||||
## Max request headers size (in bytes)
|
||||
# jetty.httpConfig.requestHeaderSize=8192
|
||||
|
||||
|
|
|
@ -828,7 +828,7 @@ public class SessionHandler extends ScopedHandler
|
|||
/**
|
||||
* Sets the max period of inactivity, after which the session is invalidated, in seconds.
|
||||
*
|
||||
* @param seconds the max inactivity period, in seconds.
|
||||
* @param seconds the max inactivity period, in seconds. If less than or equal to zero, then the session is immortal
|
||||
* @see #getMaxInactiveInterval()
|
||||
*/
|
||||
public void setMaxInactiveInterval(int seconds)
|
||||
|
|
Loading…
Reference in New Issue