diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/SimplestServer.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/SimplestServer.java index bd0540fe6ea..482194f351a 100644 --- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/SimplestServer.java +++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/SimplestServer.java @@ -29,6 +29,7 @@ public class SimplestServer { Server server = new Server(8080); server.start(); + server.dumpStdErr(); server.join(); } } diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.7.0_65.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.7.0_65.mod new file mode 100644 index 00000000000..45bbad75c9f --- /dev/null +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.7.0_65.mod @@ -0,0 +1,8 @@ +[name] +protonego-boot + +[files] +http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/7.0.0.v20140317/alpn-boot-7.0.0.v20140317.jar|lib/alpn/alpn-boot-7.0.0.v20140317.jar + +[exec] +-Xbootclasspath/p:lib/alpn/alpn-boot-7.0.0.v20140317.jar diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.8.0_11.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.8.0_11.mod new file mode 100644 index 00000000000..65e6cb3c4db --- /dev/null +++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/protonego-impl/alpn-1.8.0_11.mod @@ -0,0 +1,8 @@ +[name] +protonego-boot + +[files] +http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.0.0.v20140317/alpn-boot-8.0.0.v20140317.jar|lib/alpn/alpn-boot-8.0.0.v20140317.jar + +[exec] +-Xbootclasspath/p:lib/alpn/alpn-boot-8.0.0.v20140317.jar diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/SelectorManager.java b/jetty-io/src/main/java/org/eclipse/jetty/io/SelectorManager.java index 7904dac1a43..0e6fd889da6 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/SelectorManager.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/SelectorManager.java @@ -486,7 +486,8 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa LOG.debug("Starting {} on {}", _thread, this); while (isRunning()) select(); - runChanges(); + while(isStopping()) + runChanges(); } finally { diff --git a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/FormAuthModule.java b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/FormAuthModule.java index fbe2b62b950..9215eddaf00 100644 --- a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/FormAuthModule.java +++ b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/modules/FormAuthModule.java @@ -92,6 +92,9 @@ public class FormAuthModule extends BaseAuthModule setErrorPage(errorPage); } + /** + * @deprecated + */ public FormAuthModule(CallbackHandler callbackHandler, CrossContextPsuedoSession ssoSource, String loginPage, String errorPage) { diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/security/DataSourceLoginService.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/security/DataSourceLoginService.java index b315682f8fc..1c8edde16ba 100644 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/security/DataSourceLoginService.java +++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/security/DataSourceLoginService.java @@ -41,12 +41,11 @@ import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.UserIdentity; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.util.security.Password; +import org.eclipse.jetty.util.security.Credential; /** * - * //TODO JASPI cf JDBCLoginService * DataSourceUserRealm * * Obtain user/password/role information from a database @@ -70,6 +69,7 @@ public class DataSourceLoginService extends MappedLoginService private String _userRoleTableUserKey = "user_id"; private String _userRoleTableRoleKey = "role_id"; private int _cacheMs = 30000; + private long _lastPurge = 0; private String _userSql; private String _roleSql; private boolean _createTables = false; @@ -282,7 +282,9 @@ public class DataSourceLoginService extends MappedLoginService protected void loadUsers() { } - + + + /* ------------------------------------------------------------ */ /** Load user's info from database. * @@ -293,9 +295,8 @@ public class DataSourceLoginService extends MappedLoginService { try { - initDb(); try (Connection connection = getConnection(); - PreparedStatement statement1 = connection.prepareStatement(_userSql)) + PreparedStatement statement1 = connection.prepareStatement(_userSql)) { statement1.setObject(1, userName); try (ResultSet rs1 = statement1.executeQuery()) @@ -311,10 +312,12 @@ public class DataSourceLoginService extends MappedLoginService try (ResultSet rs2 = statement2.executeQuery()) { while (rs2.next()) + { roles.add(rs2.getString(_roleTableRoleField)); + } } } - return putUser(userName,new Password(credentials), roles.toArray(new String[roles.size()])); + return putUser(userName, Credential.getCredential(credentials), roles.toArray(new String[roles.size()])); } } } @@ -329,6 +332,22 @@ public class DataSourceLoginService extends MappedLoginService } return null; } + + + + /* ------------------------------------------------------------ */ + @Override + public UserIdentity login(String username, Object credentials) + { + long now = System.currentTimeMillis(); + if (now - _lastPurge > _cacheMs || _cacheMs == 0) + { + _users.clear(); + _lastPurge = now; + } + + return super.login(username,credentials); + } /* ------------------------------------------------------------ */ /** @@ -347,7 +366,7 @@ public class DataSourceLoginService extends MappedLoginService InitialContext ic = new InitialContext(); assert ic!=null; - //TODO webapp scope? + //TODO Should we try webapp scope too? //try finding the datasource in the Server scope if (_server != null) diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/ConstraintSecurityHandler.java b/jetty-security/src/main/java/org/eclipse/jetty/security/ConstraintSecurityHandler.java index 1bd2d52cd11..7b7f2a395e0 100644 --- a/jetty-security/src/main/java/org/eclipse/jetty/security/ConstraintSecurityHandler.java +++ b/jetty-security/src/main/java/org/eclipse/jetty/security/ConstraintSecurityHandler.java @@ -511,21 +511,6 @@ public class ConstraintSecurityHandler extends SecurityHandler implements Constr mappings.put(ALL_METHODS,roleInfo); } } - else - { - //combine with any entry that covers all methods - if (httpMethod == null) - { - for (Map.Entry entry : mappings.entrySet()) - { - if (entry.getKey() != null) - { - RoleInfo specific = entry.getValue(); - specific.combine(roleInfo); - } - } - } - } } /* ------------------------------------------------------------ */ diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/CrossContextPsuedoSession.java b/jetty-security/src/main/java/org/eclipse/jetty/security/CrossContextPsuedoSession.java index e2de9f7db22..a67eb96d6fc 100644 --- a/jetty-security/src/main/java/org/eclipse/jetty/security/CrossContextPsuedoSession.java +++ b/jetty-security/src/main/java/org/eclipse/jetty/security/CrossContextPsuedoSession.java @@ -23,6 +23,7 @@ import javax.servlet.http.HttpServletResponse; /** * @version $Rev: 4466 $ $Date: 2009-02-10 23:42:54 +0100 (Tue, 10 Feb 2009) $ + * @deprecated */ public interface CrossContextPsuedoSession { diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/HashCrossContextPsuedoSession.java b/jetty-security/src/main/java/org/eclipse/jetty/security/HashCrossContextPsuedoSession.java index 8499a609d3a..2f94908acb3 100644 --- a/jetty-security/src/main/java/org/eclipse/jetty/security/HashCrossContextPsuedoSession.java +++ b/jetty-security/src/main/java/org/eclipse/jetty/security/HashCrossContextPsuedoSession.java @@ -29,6 +29,7 @@ import javax.servlet.http.HttpServletResponse; /** * @version $Rev: 4660 $ $Date: 2009-02-25 17:29:53 +0100 (Wed, 25 Feb 2009) $ + * @deprecated */ public class HashCrossContextPsuedoSession implements CrossContextPsuedoSession { diff --git a/jetty-security/src/test/java/org/eclipse/jetty/security/ConstraintTest.java b/jetty-security/src/test/java/org/eclipse/jetty/security/ConstraintTest.java index 8897caa7124..93b32c71230 100644 --- a/jetty-security/src/test/java/org/eclipse/jetty/security/ConstraintTest.java +++ b/jetty-security/src/test/java/org/eclipse/jetty/security/ConstraintTest.java @@ -441,7 +441,7 @@ public class ConstraintTest Constraint constraint6 = new Constraint(); constraint6.setAuthenticate(true); - constraint6.setName("omit POST and GET"); + constraint6.setName("omit HEAD and GET"); constraint6.setRoles(new String[]{"user"}); ConstraintMapping mapping6 = new ConstraintMapping(); mapping6.setPathSpec("/omit/*"); diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java index c749f78b967..3106eec2575 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java @@ -186,9 +186,9 @@ public abstract class AbstractConnector extends ContainerLifeCycle implements Co int cores = Runtime.getRuntime().availableProcessors(); if (acceptors < 0) - acceptors = 1 + cores / 16; - if (acceptors > 2 * cores) - LOG.warn("Acceptors should be <= 2*availableProcessors: " + this); + acceptors=Math.max(1, Math.min(4,cores/8)); + if (acceptors > cores) + LOG.warn("Acceptors should be <= availableProcessors: " + this); _acceptors = new Thread[acceptors]; } @@ -256,7 +256,11 @@ public abstract class AbstractConnector extends ContainerLifeCycle implements Co _stopping=new CountDownLatch(_acceptors.length); for (int i = 0; i < _acceptors.length; i++) - getExecutor().execute(new Acceptor(i)); + { + Acceptor a = new Acceptor(i); + addBean(a); + getExecutor().execute(a); + } LOG.info("Started {}", this); } @@ -294,6 +298,9 @@ public abstract class AbstractConnector extends ContainerLifeCycle implements Co _stopping=null; super.doStop(); + + for (Acceptor a : getBeans(Acceptor.class)) + removeBean(a); LOG.info("Stopped {}", this); } @@ -435,6 +442,7 @@ public abstract class AbstractConnector extends ContainerLifeCycle implements Co private class Acceptor implements Runnable { private final int _acceptor; + private String _name; private Acceptor(int id) { @@ -445,8 +453,9 @@ public abstract class AbstractConnector extends ContainerLifeCycle implements Co public void run() { Thread current = Thread.currentThread(); - String name = current.getName(); - current.setName(name + "-acceptor-" + _acceptor + "-" + AbstractConnector.this); + String name=current.getName(); + _name=String.format("%s-acceptor-%d@%x-%s",name,_acceptor,hashCode(),AbstractConnector.this.toString()); + current.setName(_name); synchronized (AbstractConnector.this) { @@ -483,6 +492,16 @@ public abstract class AbstractConnector extends ContainerLifeCycle implements Co stopping.countDown(); } } + + @Override + public String toString() + { + String name=_name; + if (name==null) + return String.format("acceptor-%d@%x", _acceptor, hashCode()); + return name; + } + } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConfiguration.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConfiguration.java index 7dc54e1d654..f9c5054714f 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConfiguration.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConfiguration.java @@ -54,6 +54,23 @@ public class HttpConfiguration private boolean _sendXPoweredBy = false; //send X-Powered-By: header private boolean _sendDateHeader = true; //send Date: header + + /* ------------------------------------------------------------ */ + /** + *

An interface that allows a request object to be customized + * for a particular HTTP connector configuration. Unlike Filters, customizer are + * applied before the request is submitted for processing and can be specific to the + * connector on which the request was received. + * + *

Typically Customizers perform tasks such as:

    + *
  • process header fields that may be injected by a proxy or load balancer. + *
  • setup attributes that may come from the connection/connector such as SSL Session IDs + *
  • Allow a request to be marked as secure or authenticated if those have been offloaded + * and communicated by header, cookie or other out-of-band mechanism + *
  • Set request attributes/fields that are determined by the connector on which the + * request was received + *
+ */ public interface Customizer { public void customize(Connector connector, HttpConfiguration channelConfig, Request request); @@ -104,6 +121,7 @@ public class HttpConfiguration return _customizers; } + /* ------------------------------------------------------------ */ public T getCustomizer(Class type) { for (Customizer c : _customizers) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/SecureRequestCustomizer.java b/jetty-server/src/main/java/org/eclipse/jetty/server/SecureRequestCustomizer.java index b017461310e..dd26b04b146 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/SecureRequestCustomizer.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/SecureRequestCustomizer.java @@ -20,8 +20,10 @@ package org.eclipse.jetty.server; import java.security.cert.X509Certificate; +import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLSession; +import javax.servlet.ServletRequest; import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.io.ssl.SslConnection; @@ -31,6 +33,12 @@ import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.ssl.SslContextFactory; + +/* ------------------------------------------------------------ */ +/** Customizer that extracts the attribute from an {@link SSLContext} + * and sets them on the request with {@link ServletRequest#setAttribute(String, Object)} + * according to Servlet Specification Requirements. + */ public class SecureRequestCustomizer implements HttpConfiguration.Customizer { private static final Logger LOG = Log.getLogger(SecureRequestCustomizer.class); @@ -40,7 +48,6 @@ public class SecureRequestCustomizer implements HttpConfiguration.Customizer */ public static final String CACHED_INFO_ATTR = CachedInfo.class.getName(); - @Override public void customize(Connector connector, HttpConfiguration channelConfig, Request request) { @@ -53,14 +60,11 @@ public class SecureRequestCustomizer implements HttpConfiguration.Customizer SSLEngine sslEngine=sslConnection.getSSLEngine(); customize(sslEngine,request); } - } /* ------------------------------------------------------------ */ /* - * Allow the Listener a chance to customise the request. before the server - * does its stuff.
- * This allows the required attributes to be set for SSL requests.
+ * Customise the request attributes to be set for SSL requests.
* The requirements of the Servlet specs are: *
    *
  • an attribute named "javax.servlet.request.ssl_session_id" of type diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Server.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Server.java index 53d5c11a970..0dcdcd23900 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Server.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Server.java @@ -32,6 +32,7 @@ import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; + import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; @@ -46,11 +47,13 @@ import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.HttpURI; import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.handler.HandlerWrapper; +import org.eclipse.jetty.server.handler.StatisticsHandler; import org.eclipse.jetty.util.Attributes; import org.eclipse.jetty.util.AttributesMap; import org.eclipse.jetty.util.Jetty; import org.eclipse.jetty.util.MultiException; import org.eclipse.jetty.util.URIUtil; +import org.eclipse.jetty.util.UrlEncoded; import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedObject; import org.eclipse.jetty.util.annotation.Name; @@ -143,6 +146,25 @@ public class Server extends HandlerWrapper implements Attributes } /* ------------------------------------------------------------ */ + /** + * Set a graceful stop time. + * The {@link StatisticsHandler} must be configured so that open connections can + * be tracked for a graceful shutdown. + * @see org.eclipse.jetty.util.component.ContainerLifeCycle#setStopTimeout(long) + */ + @Override + public void setStopTimeout(long stopTimeout) + { + super.setStopTimeout(stopTimeout); + } + + /* ------------------------------------------------------------ */ + /** Set stop server at shutdown behaviour. + * @param stop If true, this server instance will be explicitly stopped when the + * JVM is shutdown. Otherwise the JVM is stopped with the server running. + * @see Runtime#addShutdownHook(Thread) + * @see ShutdownThread + */ public void setStopAtShutdown(boolean stop) { //if we now want to stop @@ -474,7 +496,6 @@ public class Server extends HandlerWrapper implements Attributes response.sendError(HttpStatus.BAD_REQUEST_400); request.setHandled(true); response.setStatus(200); - response.getHttpFields().put(HttpHeader.ALLOW,"GET,POST,HEAD,OPTIONS"); response.setContentLength(0); response.closeOutput(); } @@ -497,10 +518,11 @@ public class Server extends HandlerWrapper implements Attributes { // this is a dispatch with a path ServletContext context=event.getServletContext(); - HttpURI uri = new HttpURI(context==null?path:URIUtil.addPaths(context.getContextPath(),path)); + HttpURI uri = new HttpURI(URIUtil.encodePath(context==null?path:URIUtil.addPaths(context.getContextPath(),path))); baseRequest.setUri(uri); baseRequest.setRequestURI(null); - baseRequest.setPathInfo(baseRequest.getRequestURI()); + baseRequest.setPathInfo(uri.getDecodedPath()); + if (uri.getQuery()!=null) baseRequest.mergeQueryParameters(uri.getQuery(), true); //we have to assume dispatch path and query are UTF8 } @@ -653,6 +675,7 @@ public class Server extends HandlerWrapper implements Attributes return this.getClass().getName()+"@"+Integer.toHexString(hashCode()); } + /* ------------------------------------------------------------ */ @Override public void dump(Appendable out,String indent) throws IOException { diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ServerConnector.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ServerConnector.java index 751293da468..f4da30c004e 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/ServerConnector.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ServerConnector.java @@ -205,7 +205,8 @@ public class ServerConnector extends AbstractNetworkConnector @Name("factories") ConnectionFactory... factories) { super(server,executor,scheduler,bufferPool,acceptors,factories); - _manager = new ServerConnectorManager(getExecutor(), getScheduler(), selectors > 0 ? selectors : Runtime.getRuntime().availableProcessors()); + _manager = new ServerConnectorManager(getExecutor(), getScheduler(), + selectors>0?selectors:Math.max(1,Math.min(4,Runtime.getRuntime().availableProcessors()/2))); addBean(_manager, true); } diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/GracefulStopTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/GracefulStopTest.java index 2794cfb1f9a..01ef24fecd5 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/GracefulStopTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/GracefulStopTest.java @@ -79,6 +79,35 @@ public class GracefulStopTest Assert.assertThat(out,Matchers.containsString("200 OK")); } } + + @Test + public void testGracefulTimout() throws Exception + { + server.setStopTimeout(100); + new Thread() + { + @Override + public void run() + { + try + { + TimeUnit.SECONDS.sleep(1); + server.stop(); + } + catch (Exception e) + { + e.printStackTrace(); + } + } + }.start(); + + try(Socket socket = new Socket("localhost",server.getBean(NetworkConnector.class).getLocalPort());) + { + socket.getOutputStream().write("GET / HTTP/1.0\r\n\r\n".getBytes(StandardCharsets.ISO_8859_1)); + String out = IO.toString(socket.getInputStream()); + Assert.assertEquals("",out); + } + } private static class TestHandler extends AbstractHandler { diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpConnectionTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpConnectionTest.java index e00ddd71df9..23459d8cf80 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpConnectionTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpConnectionTest.java @@ -723,7 +723,6 @@ public class HttpConnectionTest "12345\015\012"+ "0;\015\012\015\012"); offset = checkContains(response,offset,"HTTP/1.1 200"); - offset = checkContains(response,offset,"Allow: GET,POST,HEAD"); offset=0; response=connector.getResponses("GET * HTTP/1.1\n"+ diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/PartialRFC2616Test.java b/jetty-server/src/test/java/org/eclipse/jetty/server/PartialRFC2616Test.java index 1643bab762c..bfb52afab07 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/PartialRFC2616Test.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/PartialRFC2616Test.java @@ -495,7 +495,6 @@ public class PartialRFC2616Test "Host: localhost\n"+ "\n"); offset=checkContains(response,offset, "HTTP/1.1 200","200")+1; - offset=checkContains(response,offset, "Allow: GET,POST,HEAD,OPTIONS","Allow")+1; offset=0; response=connector.getResponses("GET * HTTP/1.1\n"+ diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncServletTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncServletTest.java index a1bb491f191..288cf326349 100644 --- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncServletTest.java +++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncServletTest.java @@ -97,6 +97,7 @@ public class AsyncServletTest _servletHandler.addServletWithMapping(holder,"/path/*"); _servletHandler.addServletWithMapping(holder,"/path1/*"); _servletHandler.addServletWithMapping(holder,"/path2/*"); + _servletHandler.addServletWithMapping(holder,"/p th3/*"); _servletHandler.addServletWithMapping(new ServletHolder(new FwdServlet()),"/fwd/*"); _server.start(); _port=_connector.getLocalPort(); @@ -116,7 +117,7 @@ public class AsyncServletTest String response=process(null,null); assertEquals("HTTP/1.1 200 OK",response.substring(0,15)); assertContains( - "history: REQUEST /path\r\n"+ + "history: REQUEST /ctx/path/info\r\n"+ "history: initial\r\n",response); assertContains("NORMAL",response); assertNotContains("history: onTimeout",response); @@ -129,7 +130,7 @@ public class AsyncServletTest String response=process("sleep=200",null); assertEquals("HTTP/1.1 200 OK",response.substring(0,15)); assertContains( - "history: REQUEST /path\r\n"+ + "history: REQUEST /ctx/path/info\r\n"+ "history: initial\r\n",response); assertContains("SLEPT",response); assertNotContains("history: onTimeout",response); @@ -143,11 +144,11 @@ public class AsyncServletTest String response=process("suspend=200",null); assertEquals("HTTP/1.1 500 Async Timeout",response.substring(0,26)); assertContains( - "history: REQUEST /path\r\n"+ + "history: REQUEST /ctx/path/info\r\n"+ "history: initial\r\n"+ "history: suspend\r\n"+ "history: onTimeout\r\n"+ - "history: ERROR /path\r\n"+ + "history: ERROR /ctx/path/info\r\n"+ "history: !initial\r\n"+ "history: onComplete\r\n",response); @@ -160,12 +161,12 @@ public class AsyncServletTest String response=process("suspend=200&timeout=dispatch",null); assertEquals("HTTP/1.1 200 OK",response.substring(0,15)); assertContains( - "history: REQUEST /path\r\n"+ + "history: REQUEST /ctx/path/info\r\n"+ "history: initial\r\n"+ "history: suspend\r\n"+ "history: onTimeout\r\n"+ "history: dispatch\r\n"+ - "history: ASYNC /path\r\n"+ + "history: ASYNC /ctx/path/info\r\n"+ "history: !initial\r\n"+ "history: onComplete\r\n",response); @@ -178,7 +179,7 @@ public class AsyncServletTest String response=process("suspend=200&timeout=complete",null); assertEquals("HTTP/1.1 200 OK",response.substring(0,15)); assertContains( - "history: REQUEST /path\r\n"+ + "history: REQUEST /ctx/path/info\r\n"+ "history: initial\r\n"+ "history: suspend\r\n"+ "history: onTimeout\r\n"+ @@ -194,11 +195,11 @@ public class AsyncServletTest String response=process("suspend=200&resume=10",null); assertEquals("HTTP/1.1 200 OK",response.substring(0,15)); assertContains( - "history: REQUEST /path\r\n"+ + "history: REQUEST /ctx/path/info\r\n"+ "history: initial\r\n"+ "history: suspend\r\n"+ "history: resume\r\n"+ - "history: ASYNC /path\r\n"+ + "history: ASYNC /ctx/path/info\r\n"+ "history: !initial\r\n"+ "history: onComplete\r\n",response); assertNotContains("history: onTimeout",response); @@ -210,11 +211,11 @@ public class AsyncServletTest String response=process("suspend=200&resume=0",null); assertEquals("HTTP/1.1 200 OK",response.substring(0,15)); assertContains( - "history: REQUEST /path\r\n"+ + "history: REQUEST /ctx/path/info\r\n"+ "history: initial\r\n"+ "history: suspend\r\n"+ "history: resume\r\n"+ - "history: ASYNC /path\r\n"+ + "history: ASYNC /ctx/path/info\r\n"+ "history: !initial\r\n"+ "history: onComplete\r\n",response); assertContains("history: onComplete",response); @@ -226,7 +227,7 @@ public class AsyncServletTest String response=process("suspend=200&complete=50",null); assertEquals("HTTP/1.1 200 OK",response.substring(0,15)); assertContains( - "history: REQUEST /path\r\n"+ + "history: REQUEST /ctx/path/info\r\n"+ "history: initial\r\n"+ "history: suspend\r\n"+ "history: complete\r\n"+ @@ -242,7 +243,7 @@ public class AsyncServletTest String response=process("suspend=200&complete=0",null); assertEquals("HTTP/1.1 200 OK",response.substring(0,15)); assertContains( - "history: REQUEST /path\r\n"+ + "history: REQUEST /ctx/path/info\r\n"+ "history: initial\r\n"+ "history: suspend\r\n"+ "history: complete\r\n"+ @@ -258,15 +259,15 @@ public class AsyncServletTest String response=process("suspend=1000&resume=10&suspend2=1000&resume2=10",null); assertEquals("HTTP/1.1 200 OK",response.substring(0,15)); assertContains( - "history: REQUEST /path\r\n"+ + "history: REQUEST /ctx/path/info\r\n"+ "history: initial\r\n"+ "history: suspend\r\n"+ "history: resume\r\n"+ - "history: ASYNC /path\r\n"+ + "history: ASYNC /ctx/path/info\r\n"+ "history: !initial\r\n"+ "history: suspend\r\n"+ "history: resume\r\n"+ - "history: ASYNC /path\r\n"+ + "history: ASYNC /ctx/path/info\r\n"+ "history: !initial\r\n"+ "history: onComplete\r\n",response); assertContains("DISPATCHED",response); @@ -278,11 +279,11 @@ public class AsyncServletTest String response=process("suspend=1000&resume=10&suspend2=1000&complete2=10",null); assertEquals("HTTP/1.1 200 OK",response.substring(0,15)); assertContains( - "history: REQUEST /path\r\n"+ + "history: REQUEST /ctx/path/info\r\n"+ "history: initial\r\n"+ "history: suspend\r\n"+ "history: resume\r\n"+ - "history: ASYNC /path\r\n"+ + "history: ASYNC /ctx/path/info\r\n"+ "history: !initial\r\n"+ "history: suspend\r\n"+ "history: complete\r\n"+ @@ -297,15 +298,15 @@ public class AsyncServletTest String response=process("suspend=1000&resume=10&suspend2=10",null); assertEquals("HTTP/1.1 500 Async Timeout",response.substring(0,26)); assertContains( - "history: REQUEST /path\r\n"+ + "history: REQUEST /ctx/path/info\r\n"+ "history: initial\r\n"+ "history: suspend\r\n"+ "history: resume\r\n"+ - "history: ASYNC /path\r\n"+ + "history: ASYNC /ctx/path/info\r\n"+ "history: !initial\r\n"+ "history: suspend\r\n"+ "history: onTimeout\r\n"+ - "history: ERROR /path\r\n"+ + "history: ERROR /ctx/path/info\r\n"+ "history: !initial\r\n"+ "history: onComplete\r\n",response); assertContains("ERROR: /ctx/path/info",response); @@ -317,15 +318,15 @@ public class AsyncServletTest String response=process("suspend=10&suspend2=1000&resume2=10",null); assertEquals("HTTP/1.1 200 OK",response.substring(0,15)); assertContains( - "history: REQUEST /path\r\n"+ + "history: REQUEST /ctx/path/info\r\n"+ "history: initial\r\n"+ "history: suspend\r\n"+ "history: onTimeout\r\n"+ - "history: ERROR /path\r\n"+ + "history: ERROR /ctx/path/info\r\n"+ "history: !initial\r\n"+ "history: suspend\r\n"+ "history: resume\r\n"+ - "history: ASYNC /path\r\n"+ + "history: ASYNC /ctx/path/info\r\n"+ "history: !initial\r\n"+ "history: onComplete\r\n",response); assertContains("DISPATCHED",response); @@ -337,11 +338,11 @@ public class AsyncServletTest String response=process("suspend=10&suspend2=1000&complete2=10",null); assertEquals("HTTP/1.1 200 OK",response.substring(0,15)); assertContains( - "history: REQUEST /path\r\n"+ + "history: REQUEST /ctx/path/info\r\n"+ "history: initial\r\n"+ "history: suspend\r\n"+ "history: onTimeout\r\n"+ - "history: ERROR /path\r\n"+ + "history: ERROR /ctx/path/info\r\n"+ "history: !initial\r\n"+ "history: suspend\r\n"+ "history: complete\r\n"+ @@ -355,15 +356,15 @@ public class AsyncServletTest _expectedCode="500 "; String response=process("suspend=10&suspend2=10",null); assertContains( - "history: REQUEST /path\r\n"+ + "history: REQUEST /ctx/path/info\r\n"+ "history: initial\r\n"+ "history: suspend\r\n"+ "history: onTimeout\r\n"+ - "history: ERROR /path\r\n"+ + "history: ERROR /ctx/path/info\r\n"+ "history: !initial\r\n"+ "history: suspend\r\n"+ "history: onTimeout\r\n"+ - "history: ERROR /path\r\n"+ + "history: ERROR /ctx/path/info\r\n"+ "history: !initial\r\n"+ "history: onComplete\r\n",response); assertContains("ERROR: /ctx/path/info",response); @@ -375,30 +376,48 @@ public class AsyncServletTest String response=process("wrap=true&suspend=200&resume=20",null); assertEquals("HTTP/1.1 200 OK",response.substring(0,15)); assertContains( - "history: REQUEST /path\r\n"+ + "history: REQUEST /ctx/path/info\r\n"+ "history: initial\r\n"+ "history: suspend\r\n"+ "history: resume\r\n"+ - "history: ASYNC /path\r\n"+ + "history: ASYNC /ctx/path/info\r\n"+ "history: wrapped REQ RSP\r\n"+ "history: !initial\r\n"+ "history: onComplete\r\n",response); assertContains("DISPATCHED",response); } + + @Test + public void testStartDispatchEncodedPath() throws Exception + { + String response=process("suspend=200&resume=20&path=/p%20th3",null); + assertEquals("HTTP/1.1 200 OK",response.substring(0,15)); + assertContains( + "history: REQUEST /ctx/path/info\r\n"+ + "history: initial\r\n"+ + "history: suspend\r\n"+ + "history: resume\r\n"+ + "history: ASYNC /ctx/p%20th3\r\n"+ + "history: !initial\r\n"+ + "history: onComplete\r\n",response); + assertContains("DISPATCHED",response); + } + + @Test public void testFwdStartDispatch() throws Exception { String response=process("fwd","suspend=200&resume=20",null); assertEquals("HTTP/1.1 200 OK",response.substring(0,15)); assertContains( - "history: FWD REQUEST /fwd\r\n"+ - "history: FORWARD /path1\r\n"+ + "history: FWD REQUEST /ctx/fwd/info\r\n"+ + "history: FORWARD /ctx/path1\r\n"+ "history: initial\r\n"+ "history: suspend\r\n"+ "history: resume\r\n"+ - "history: FWD ASYNC /fwd\r\n"+ - "history: FORWARD /path1\r\n"+ + "history: FWD ASYNC /ctx/fwd/info\r\n"+ + "history: FORWARD /ctx/path1\r\n"+ "history: !initial\r\n"+ "history: onComplete\r\n",response); assertContains("DISPATCHED",response); @@ -410,12 +429,12 @@ public class AsyncServletTest String response=process("fwd","suspend=200&resume=20&path=/path2",null); assertEquals("HTTP/1.1 200 OK",response.substring(0,15)); assertContains( - "history: FWD REQUEST /fwd\r\n"+ - "history: FORWARD /path1\r\n"+ + "history: FWD REQUEST /ctx/fwd/info\r\n"+ + "history: FORWARD /ctx/path1\r\n"+ "history: initial\r\n"+ "history: suspend\r\n"+ "history: resume\r\n"+ - "history: ASYNC /path2\r\n"+ + "history: ASYNC /ctx/path2\r\n"+ "history: !initial\r\n"+ "history: onComplete\r\n",response); assertContains("DISPATCHED",response); @@ -427,12 +446,12 @@ public class AsyncServletTest String response=process("fwd","wrap=true&suspend=200&resume=20",null); assertEquals("HTTP/1.1 200 OK",response.substring(0,15)); assertContains( - "history: FWD REQUEST /fwd\r\n"+ - "history: FORWARD /path1\r\n"+ + "history: FWD REQUEST /ctx/fwd/info\r\n"+ + "history: FORWARD /ctx/path1\r\n"+ "history: initial\r\n"+ "history: suspend\r\n"+ "history: resume\r\n"+ - "history: ASYNC /path1\r\n"+ + "history: ASYNC /ctx/path1\r\n"+ "history: wrapped REQ RSP\r\n"+ "history: !initial\r\n"+ "history: onComplete\r\n",response); @@ -445,12 +464,12 @@ public class AsyncServletTest String response=process("fwd","wrap=true&suspend=200&resume=20&path=/path2",null); assertEquals("HTTP/1.1 200 OK",response.substring(0,15)); assertContains( - "history: FWD REQUEST /fwd\r\n"+ - "history: FORWARD /path1\r\n"+ + "history: FWD REQUEST /ctx/fwd/info\r\n"+ + "history: FORWARD /ctx/path1\r\n"+ "history: initial\r\n"+ "history: suspend\r\n"+ "history: resume\r\n"+ - "history: ASYNC /path2\r\n"+ + "history: ASYNC /ctx/path2\r\n"+ "history: wrapped REQ RSP\r\n"+ "history: !initial\r\n"+ "history: onComplete\r\n",response); @@ -485,12 +504,12 @@ public class AsyncServletTest String response = IO.toString(socket.getInputStream()); assertEquals("HTTP/1.1 200 OK",response.substring(0,15)); assertContains( - "history: REQUEST /path\r\n"+ + "history: REQUEST /ctx/path/info\r\n"+ "history: initial\r\n"+ "history: suspend\r\n"+ "history: async-read=10\r\n"+ "history: resume\r\n"+ - "history: ASYNC /path\r\n"+ + "history: ASYNC /ctx/path/info\r\n"+ "history: !initial\r\n"+ "history: onComplete\r\n",response); } @@ -548,7 +567,7 @@ public class AsyncServletTest @Override public void doGet(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException { - response.addHeader("history","FWD "+request.getDispatcherType()+" "+request.getServletPath()); + response.addHeader("history","FWD "+request.getDispatcherType()+" "+request.getRequestURI()); if (request instanceof ServletRequestWrapper || response instanceof ServletResponseWrapper) response.addHeader("history","wrapped"+((request instanceof ServletRequestWrapper)?" REQ":"")+((response instanceof ServletResponseWrapper)?" RSP":"")); request.getServletContext().getRequestDispatcher("/path1").forward(request,response); @@ -564,7 +583,7 @@ public class AsyncServletTest public void doGet(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException { // System.err.println(request.getDispatcherType()+" "+request.getRequestURI()); - response.addHeader("history",request.getDispatcherType()+" "+request.getServletPath()); + response.addHeader("history",request.getDispatcherType()+" "+request.getRequestURI()); if (request instanceof ServletRequestWrapper || response instanceof ServletResponseWrapper) response.addHeader("history","wrapped"+((request instanceof ServletRequestWrapper)?" REQ":"")+((response instanceof ServletResponseWrapper)?" RSP":"")); diff --git a/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_65.mod b/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_65.mod new file mode 100644 index 00000000000..639c70e3ffd --- /dev/null +++ b/jetty-spdy/spdy-http-server/src/main/config/modules/protonego-impl/npn-1.7.0_65.mod @@ -0,0 +1,8 @@ +[name] +protonego-boot + +[files] +http://central.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.7.v20140316/npn-boot-1.1.7.v20140316.jar|lib/npn/npn-boot-1.1.7.v20140316.jar + +[exec] +-Xbootclasspath/p:lib/npn/npn-boot-1.1.7.v20140316.jar diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/Main.java b/jetty-start/src/main/java/org/eclipse/jetty/start/Main.java index 22e7a462333..965333b9d65 100644 --- a/jetty-start/src/main/java/org/eclipse/jetty/start/Main.java +++ b/jetty-start/src/main/java/org/eclipse/jetty/start/Main.java @@ -136,6 +136,7 @@ public class Main } private BaseHome baseHome; + private StartArgs startupArgs; public Main() throws IOException { @@ -658,19 +659,7 @@ public class Main if (args.isStopCommand()) { - int stopPort = Integer.parseInt(args.getProperties().getString("STOP.PORT")); - String stopKey = args.getProperties().getString("STOP.KEY"); - - if (args.getProperties().getString("STOP.WAIT") != null) - { - int stopWait = Integer.parseInt(args.getProperties().getString("STOP.PORT")); - - stop(stopPort,stopKey,stopWait); - } - else - { - stop(stopPort,stopKey); - } + doStop(args); } // Initialize start.ini @@ -760,6 +749,22 @@ public class Main } } + private void doStop(StartArgs args) { + int stopPort = Integer.parseInt(args.getProperties().getString("STOP.PORT")); + String stopKey = args.getProperties().getString("STOP.KEY"); + + if (args.getProperties().getString("STOP.WAIT") != null) + { + int stopWait = Integer.parseInt(args.getProperties().getString("STOP.PORT")); + + stop(stopPort,stopKey,stopWait); + } + else + { + stop(stopPort,stopKey); + } + } + /** * Stop a running jetty instance. */ @@ -867,4 +872,37 @@ public class Main System.exit(EXIT_USAGE); } } + + // ------------------------------------------------------------ + // implement Apache commons daemon (jsvc) lifecycle methods (init, start, stop, destroy) + public void init(String[] args) throws Exception + { + try + { + startupArgs = processCommandLine(args); + } + catch (UsageException e) + { + System.err.println(e.getMessage()); + usageExit(e.getCause(),e.getExitCode()); + } + catch (Throwable e) + { + usageExit(e,UsageException.ERR_UNKNOWN); + } + } + + public void start() throws Exception + { + start(startupArgs); + } + + public void stop() throws Exception + { + doStop(startupArgs); + } + + public void destroy() + { + } } diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/security/Credential.java b/jetty-util/src/main/java/org/eclipse/jetty/util/security/Credential.java index 1feb604790f..3db90dca446 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/security/Credential.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/security/Credential.java @@ -160,17 +160,19 @@ public abstract class Credential implements Serializable digest = __md.digest(); } if (digest == null || digest.length != _digest.length) return false; + boolean digestMismatch = false; for (int i = 0; i < digest.length; i++) - if (digest[i] != _digest[i]) return false; - return true; + digestMismatch |= (digest[i] != _digest[i]); + return !digestMismatch; } else if (credentials instanceof MD5) { MD5 md5 = (MD5) credentials; if (_digest.length != md5._digest.length) return false; + boolean digestMismatch = false; for (int i = 0; i < _digest.length; i++) - if (_digest[i] != md5._digest[i]) return false; - return true; + digestMismatch |= (_digest[i] != md5._digest[i]); + return !digestMismatch; } else if (credentials instanceof Credential) { diff --git a/pom.xml b/pom.xml index 90085404d2f..e18b4c5383f 100644 --- a/pom.xml +++ b/pom.xml @@ -894,6 +894,19 @@ 7.0.0.v20140317 + + 7u65 + + + java.version + 1.7.0_65 + + + + 1.1.7.v20140316 + 7.0.0.v20140317 + + 8u00 @@ -918,6 +931,18 @@ 8.0.0.v20140317 + + 8u11 + + + java.version + 1.8.0_11 + + + + 8.0.0.v20140317 + + diff --git a/tests/test-loginservice/pom.xml b/tests/test-loginservice/pom.xml index 88d2e6783a2..75fc5d95035 100644 --- a/tests/test-loginservice/pom.xml +++ b/tests/test-loginservice/pom.xml @@ -27,42 +27,52 @@ Jetty Tests :: Login Service http://www.eclipse.org/jetty - - org.eclipse.jetty - jetty-server - ${project.version} - - - org.eclipse.jetty - jetty-webapp - ${project.version} - - - org.eclipse.jetty - jetty-client - ${project.version} - - - org.eclipse.jetty - jetty-security - ${project.version} - - - org.apache.derby - derby - 10.4.1.3 - test - - - org.apache.derby - derbytools - 10.4.1.3 - test - - - org.eclipse.jetty.toolchain - jetty-test-helper - test - + + org.eclipse.jetty + jetty-server + ${project.version} + + + org.eclipse.jetty + jetty-webapp + ${project.version} + + + org.eclipse.jetty + jetty-client + ${project.version} + + + org.eclipse.jetty + jetty-security + ${project.version} + + + org.eclipse.jetty + jetty-plus + ${project.version} + + + org.eclipse.jetty + jetty-jndi + ${project.version} + + + org.apache.derby + derby + 10.4.1.3 + test + + + org.apache.derby + derbytools + 10.4.1.3 + test + + + org.eclipse.jetty.toolchain + jetty-test-helper + test + diff --git a/tests/test-loginservice/src/test/java/org/eclipse/jetty/DataSourceLoginServiceTest.java b/tests/test-loginservice/src/test/java/org/eclipse/jetty/DataSourceLoginServiceTest.java new file mode 100644 index 00000000000..b635cb59804 --- /dev/null +++ b/tests/test-loginservice/src/test/java/org/eclipse/jetty/DataSourceLoginServiceTest.java @@ -0,0 +1,189 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + + +package org.eclipse.jetty; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; + +import java.io.File; +import java.io.FileOutputStream; +import java.net.URI; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.Statement; +import java.util.concurrent.TimeUnit; + +import javax.servlet.http.HttpServletResponse; + +import org.apache.derby.jdbc.EmbeddedDataSource; +import org.eclipse.jetty.client.HttpClient; +import org.eclipse.jetty.client.api.AuthenticationStore; +import org.eclipse.jetty.client.api.ContentResponse; +import org.eclipse.jetty.client.util.BasicAuthentication; +import org.eclipse.jetty.plus.security.DataSourceLoginService; +import org.eclipse.jetty.toolchain.test.FS; +import org.eclipse.jetty.toolchain.test.MavenTestingUtils; +import org.eclipse.jetty.util.Loader; +import org.eclipse.jetty.util.thread.QueuedThreadPool; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +/** + * DataSourceLoginServiceTest + * + * + */ +public class DataSourceLoginServiceTest +{ + public static final String _content = "This is some protected content"; + private static File _docRoot; + private static File _dbRoot; + private static HttpClient _client; + private static String __realm = "DSRealm"; + private static URI _baseUri; + private static final int __cacheInterval = 200; + private static DatabaseLoginServiceTestServer _testServer; + + @BeforeClass + public static void setUp() throws Exception + { + _docRoot = MavenTestingUtils.getTargetTestingDir(DataSourceLoginServiceTest.class.getSimpleName()); + FS.ensureEmpty(_docRoot); + + File content = new File(_docRoot,"input.txt"); + FileOutputStream out = new FileOutputStream(content); + out.write(_content.getBytes("utf-8")); + out.close(); + + File scriptFile = MavenTestingUtils.getTestResourceFile("createdb.sql"); + _dbRoot = DatabaseLoginServiceTestServer.createDB(scriptFile,"dstest"); + + _testServer = new DatabaseLoginServiceTestServer(); + _testServer.setResourceBase(_docRoot.getAbsolutePath()); + _testServer.setLoginService(configureLoginService()); + _testServer.start(); + _baseUri = _testServer.getBaseUri(); + } + + @AfterClass + public static void tearDown() + throws Exception + { + if (_testServer != null) + { + _testServer.stop(); + _testServer = null; + } + } + + public static DataSourceLoginService configureLoginService () throws Exception + { + DataSourceLoginService loginService = new DataSourceLoginService(); + loginService.setUserTableName("users"); + loginService.setUserTableKey("id"); + loginService.setUserTableUserField("username"); + loginService.setUserTablePasswordField("pwd"); + loginService.setRoleTableName("roles"); + loginService.setRoleTableKey("id"); + loginService.setRoleTableRoleField("role"); + loginService.setUserRoleTableName("user_roles"); + loginService.setUserRoleTableRoleKey("role_id"); + loginService.setUserRoleTableUserKey("user_id"); + loginService.setJndiName("dstest"); + loginService.setName(__realm); + loginService.setCacheMs(__cacheInterval); + if (_testServer != null) + loginService.setServer(_testServer.getServer()); + + //create a datasource + EmbeddedDataSource ds = new EmbeddedDataSource(); + ds.setDatabaseName(_dbRoot.getAbsolutePath()); + org.eclipse.jetty.plus.jndi.Resource binding = new org.eclipse.jetty.plus.jndi.Resource(null, "dstest", + ds); + assertThat("Created binding for dstest", binding, notNullValue()); + return loginService; + } + + @Test + public void testGetAndPasswordUpdate() throws Exception + { + try + { + startClient("jetty", "jetty"); + + ContentResponse response = _client.GET(_baseUri.resolve("input.txt")); + assertEquals(HttpServletResponse.SC_OK,response.getStatus()); + assertEquals(_content, response.getContentAsString()); + + stopClient(); + + String newpwd = String.valueOf(System.currentTimeMillis()); + + changePassword("jetty", newpwd); + TimeUnit.MILLISECONDS.sleep(2*__cacheInterval); //pause to ensure cache invalidates + + startClient("jetty", newpwd); + + response = _client.GET(_baseUri.resolve("input.txt")); + assertEquals(HttpServletResponse.SC_OK,response.getStatus()); + assertEquals(_content, response.getContentAsString()); + + } + finally + { + stopClient(); + } + } + + + protected void changePassword (String user, String newpwd) throws Exception + { + Loader.loadClass(this.getClass(), "org.apache.derby.jdbc.EmbeddedDriver").newInstance(); + try (Connection connection = DriverManager.getConnection("jdbc:derby:dstest", "", "")) + { + Statement stmt = connection.createStatement(); + stmt.executeUpdate("update users set pwd='"+newpwd+"' where username='"+user+"'"); + } + + } + + + protected void startClient(String user, String pwd) throws Exception + { + _client = new HttpClient(); + QueuedThreadPool executor = new QueuedThreadPool(); + executor.setName(executor.getName() + "-client"); + _client.setExecutor(executor); + AuthenticationStore authStore = _client.getAuthenticationStore(); + authStore.addAuthentication(new BasicAuthentication(_baseUri, __realm, user, pwd)); + _client.start(); + } + + protected void stopClient() throws Exception + { + if (_client != null) + { + _client.stop(); + _client = null; + } + } + +} diff --git a/tests/test-loginservice/src/test/java/org/eclipse/jetty/DatabaseLoginServiceTestServer.java b/tests/test-loginservice/src/test/java/org/eclipse/jetty/DatabaseLoginServiceTestServer.java new file mode 100644 index 00000000000..322e407c65c --- /dev/null +++ b/tests/test-loginservice/src/test/java/org/eclipse/jetty/DatabaseLoginServiceTestServer.java @@ -0,0 +1,252 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + + +package org.eclipse.jetty; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.net.URI; +import java.net.URLDecoder; +import java.sql.Connection; +import java.sql.DriverManager; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import javax.servlet.ServletException; +import javax.servlet.ServletInputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.derby.tools.ij; +import org.eclipse.jetty.security.ConstraintMapping; +import org.eclipse.jetty.security.ConstraintSecurityHandler; +import org.eclipse.jetty.security.LoginService; +import org.eclipse.jetty.security.authentication.BasicAuthenticator; +import org.eclipse.jetty.server.Handler; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.handler.AbstractHandler; +import org.eclipse.jetty.server.handler.HandlerCollection; +import org.eclipse.jetty.servlet.DefaultServlet; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.eclipse.jetty.toolchain.test.FS; +import org.eclipse.jetty.toolchain.test.MavenTestingUtils; +import org.eclipse.jetty.util.IO; +import org.eclipse.jetty.util.Loader; +import org.eclipse.jetty.util.security.Constraint; + + +/** + * DatabaseLoginServiceTestServer + */ +public class DatabaseLoginServiceTestServer +{ + protected Server _server; + protected static String _protocol; + protected static URI _baseUri; + protected LoginService _loginService; + protected String _resourceBase; + protected TestHandler _handler; + private static File commonDerbySystemHome; + protected static String _requestContent; + + protected static File createDB(File scriptFile, String dbName) throws Exception + { + if(commonDerbySystemHome == null) + { + commonDerbySystemHome = MavenTestingUtils.getTargetTestingDir("derby-system-common"); + FS.ensureEmpty(commonDerbySystemHome); + System.setProperty("derby.system.home", commonDerbySystemHome.getAbsolutePath()); + } + + String dbUrl = "jdbc:derby:directory:" + dbName + ";create=true"; + + try (FileInputStream fileStream = new FileInputStream(scriptFile)) + { + Loader.loadClass(fileStream.getClass(), "org.apache.derby.jdbc.EmbeddedDriver").newInstance(); + Connection connection = DriverManager.getConnection(dbUrl, "", ""); + + OutputStream out = new ByteArrayOutputStream(); + int result = ij.runScript(connection, fileStream, "UTF-8", out, "UTF-8"); + + assertThat("runScript result",result, is(0)); + + File dbRoot = new File(commonDerbySystemHome, dbName); + assertThat("exists: " + dbRoot, dbRoot.exists(), is(true)); + return dbRoot; + } + } + + public static class TestHandler extends AbstractHandler + { + private final String _resourcePath; + private String _requestContent; + + + public TestHandler(String repositoryPath) + { + _resourcePath = repositoryPath; + } + + public void handle(String target, org.eclipse.jetty.server.Request baseRequest, + HttpServletRequest request, HttpServletResponse response) + throws IOException, ServletException + { + if (baseRequest.isHandled()) + { + return; + } + + OutputStream out = null; + + if (baseRequest.getMethod().equals("PUT")) + { + baseRequest.setHandled(true); + + File file = new File(_resourcePath, URLDecoder.decode(request.getPathInfo(), "utf-8")); + FS.ensureDirExists(file.getParentFile()); + + out = new FileOutputStream(file); + + response.setStatus(HttpServletResponse.SC_CREATED); + } + + if (baseRequest.getMethod().equals("POST")) + { + baseRequest.setHandled(true); + out = new ByteArrayOutputStream(); + + response.setStatus(HttpServletResponse.SC_OK); + } + + if (out != null) + { + try (ServletInputStream in = request.getInputStream()) + { + IO.copy(in, out); + } + finally + { + out.close(); + } + + if (!(out instanceof FileOutputStream)) + _requestContent = out.toString(); + } + } + + public String getRequestContent() + { + return _requestContent; + } + } + + + public DatabaseLoginServiceTestServer () + { + _server = new Server(0); + } + + public void setLoginService (LoginService loginService) + { + _loginService = loginService; + } + + public void setResourceBase (String resourceBase) + { + _resourceBase = resourceBase; + } + + + public void start () throws Exception + { + configureServer(); + _server.start(); + //_server.dumpStdErr(); + _baseUri = _server.getURI(); + } + + public void stop() throws Exception + { + _server.stop(); + } + + public URI getBaseUri() + { + return _baseUri; + } + + public TestHandler getTestHandler() + { + return _handler; + } + + public Server getServer() + { + return _server; + } + + protected void configureServer() throws Exception + { + _protocol = "http"; + _server.addBean(_loginService); + + ConstraintSecurityHandler security = new ConstraintSecurityHandler(); + _server.setHandler(security); + + Constraint constraint = new Constraint(); + constraint.setName("auth"); + constraint.setAuthenticate( true ); + constraint.setRoles(new String[]{"user", "admin"}); + + ConstraintMapping mapping = new ConstraintMapping(); + mapping.setPathSpec( "/*" ); + mapping.setConstraint( constraint ); + + Set knownRoles = new HashSet<>(); + knownRoles.add("user"); + knownRoles.add("admin"); + + security.setConstraintMappings(Collections.singletonList(mapping), knownRoles); + security.setAuthenticator(new BasicAuthenticator()); + security.setLoginService(_loginService); + + ServletContextHandler root = new ServletContextHandler(); + root.setContextPath("/"); + root.setResourceBase(_resourceBase); + ServletHolder servletHolder = new ServletHolder( new DefaultServlet() ); + servletHolder.setInitParameter( "gzip", "true" ); + root.addServlet( servletHolder, "/*" ); + + _handler = new TestHandler(_resourceBase); + + HandlerCollection handlers = new HandlerCollection(); + handlers.setHandlers(new Handler[]{_handler, root}); + security.setHandler(handlers); + } + +} diff --git a/tests/test-loginservice/src/test/java/org/eclipse/jetty/JdbcLoginServiceTest.java b/tests/test-loginservice/src/test/java/org/eclipse/jetty/JdbcLoginServiceTest.java index 543b0773307..8ff5aa8d524 100644 --- a/tests/test-loginservice/src/test/java/org/eclipse/jetty/JdbcLoginServiceTest.java +++ b/tests/test-loginservice/src/test/java/org/eclipse/jetty/JdbcLoginServiceTest.java @@ -21,27 +21,13 @@ package org.eclipse.jetty; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; -import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; import java.net.URI; -import java.net.URLDecoder; -import java.sql.Connection; -import java.sql.DriverManager; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; -import javax.servlet.ServletException; -import javax.servlet.ServletInputStream; -import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.apache.derby.tools.ij; import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.client.api.AuthenticationStore; import org.eclipse.jetty.client.api.ContentResponse; @@ -50,23 +36,11 @@ import org.eclipse.jetty.client.util.BasicAuthentication; import org.eclipse.jetty.client.util.BytesContentProvider; import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpStatus; -import org.eclipse.jetty.io.EofException; -import org.eclipse.jetty.security.ConstraintMapping; -import org.eclipse.jetty.security.ConstraintSecurityHandler; import org.eclipse.jetty.security.JDBCLoginService; import org.eclipse.jetty.security.LoginService; -import org.eclipse.jetty.security.authentication.BasicAuthenticator; -import org.eclipse.jetty.server.Handler; -import org.eclipse.jetty.server.NetworkConnector; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.handler.AbstractHandler; -import org.eclipse.jetty.server.handler.HandlerCollection; -import org.eclipse.jetty.servlet.DefaultServlet; -import org.eclipse.jetty.servlet.ServletContextHandler; -import org.eclipse.jetty.servlet.ServletHolder; +import org.eclipse.jetty.toolchain.test.FS; +import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.eclipse.jetty.util.IO; -import org.eclipse.jetty.util.Loader; -import org.eclipse.jetty.util.security.Constraint; import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.junit.AfterClass; import org.junit.BeforeClass; @@ -90,127 +64,45 @@ public class JdbcLoginServiceTest "et cursus magna. Donec orci enim, molestie a lobortis eu, imperdiet vitae neque."; private static File _docRoot; - private static Server _server; private static HttpClient _client; private static String __realm = "JdbcRealm"; - private static String _protocol; - private static String _baseUrl; - private static String _requestContent; - - protected static boolean createDB(String homeDir, String fileName, String dbUrl) - { - FileInputStream fileStream = null; - try - { - File scriptFile = new File(fileName); - fileStream = new FileInputStream(scriptFile); - - Loader.loadClass(fileStream.getClass(), "org.apache.derby.jdbc.EmbeddedDriver").newInstance(); - Connection connection = DriverManager.getConnection(dbUrl, "", ""); - - OutputStream out = new ByteArrayOutputStream(); - int result = ij.runScript(connection, fileStream, "UTF-8", out, "UTF-8"); - - return (result==0); - } - catch (Exception e) - { - return false; - } - finally { - if (fileStream!=null) - { - try - { - fileStream.close(); - } - catch (IOException e) {} - } - } - } - - protected static void configureServer(Server server) - throws Exception - { - setProtocol("http"); - - LoginService loginService = new JDBCLoginService(__realm, "./src/test/resources/jdbcrealm.properties"); - server.addBean(loginService); - - ConstraintSecurityHandler security = new ConstraintSecurityHandler(); - server.setHandler(security); - - Constraint constraint = new Constraint(); - constraint.setName("auth"); - constraint.setAuthenticate( true ); - constraint.setRoles(new String[]{"user", "admin"}); - - ConstraintMapping mapping = new ConstraintMapping(); - mapping.setPathSpec( "/*" ); - mapping.setConstraint( constraint ); - - Set knownRoles = new HashSet<>(); - knownRoles.add("user"); - knownRoles.add("admin"); - - security.setConstraintMappings(Collections.singletonList(mapping), knownRoles); - security.setAuthenticator(new BasicAuthenticator()); - security.setLoginService(loginService); - - ServletContextHandler root = new ServletContextHandler(); - root.setContextPath("/"); - root.setResourceBase(getBasePath()); - ServletHolder servletHolder = new ServletHolder( new DefaultServlet() ); - servletHolder.setInitParameter( "gzip", "true" ); - root.addServlet( servletHolder, "/*" ); - - Handler handler = new TestHandler(getBasePath()); - - HandlerCollection handlers = new HandlerCollection(); - handlers.setHandlers(new Handler[]{handler, root}); - security.setHandler(handlers); - } + private static URI _baseUri; + private static DatabaseLoginServiceTestServer _testServer; @BeforeClass - public static void setUp() - throws Exception - { - _docRoot = new File("target/test-output/docroot/"); - _docRoot.mkdirs(); - _docRoot.deleteOnExit(); - - File content = new File(_docRoot,"input.txt"); - FileOutputStream out = new FileOutputStream(content); - out.write(_content.getBytes("utf-8")); - out.close(); - - File dbRoot = new File("target/test-output/derby"); - String dbPath = dbRoot.getAbsolutePath(); - System.setProperty("derby.system.home", dbPath); - if (!dbRoot.exists()) - { - dbRoot.mkdirs(); - createDB(dbPath, "src/test/resources/createdb.sql", "jdbc:derby:jdbcrealm;create=true"); - } - - _server = new Server(0); - configureServer(_server); - _server.start(); - - int port = ((NetworkConnector)_server.getConnectors()[0]).getLocalPort(); - _baseUrl = _protocol+"://localhost:"+port+ "/"; - + public static void setUp() throws Exception + { + _docRoot = MavenTestingUtils.getTargetTestingDir(JdbcLoginServiceTest.class.getSimpleName()); + FS.ensureEmpty(_docRoot); + File content = new File(_docRoot,"input.txt"); + + try (FileOutputStream out = new FileOutputStream(content)) + { + out.write(_content.getBytes("utf-8")); + } + + File scriptFile = MavenTestingUtils.getTestResourceFile("createdb.sql"); + DatabaseLoginServiceTestServer.createDB(scriptFile,"jdbcrealm"); + + File jdbcRealmFile = MavenTestingUtils.getTestResourceFile("jdbcrealm.properties"); + + LoginService loginService = new JDBCLoginService(__realm, jdbcRealmFile.getAbsolutePath()); + _testServer = new DatabaseLoginServiceTestServer(); + _testServer.setResourceBase(_docRoot.getAbsolutePath()); + _testServer.setLoginService(loginService); + _testServer.start(); + _baseUri = _testServer.getBaseUri(); } @AfterClass public static void tearDown() throws Exception { - if (_server != null) + if (_testServer != null) { - _server.stop(); - _server = null; + _testServer.stop(); + _testServer = null; } } @@ -221,7 +113,7 @@ public class JdbcLoginServiceTest { startClient(); - Request request = _client.newRequest(getBaseUrl() + "output.txt"); + Request request = _client.newRequest(_baseUri.resolve("output.txt")); request.method(HttpMethod.PUT); request.content(new BytesContentProvider(_content.getBytes())); ContentResponse response = request.send(); @@ -244,7 +136,7 @@ public class JdbcLoginServiceTest { startClient(); - ContentResponse response = _client.GET(getBaseUrl() + "input.txt"); + ContentResponse response = _client.GET(_baseUri.resolve("input.txt")); assertEquals(HttpServletResponse.SC_OK,response.getStatus()); assertEquals(_content, response.getContentAsString()); } @@ -262,7 +154,7 @@ public class JdbcLoginServiceTest { startClient(); - Request request = _client.newRequest(getBaseUrl() + "input.txt"); + Request request = _client.newRequest(_baseUri.resolve("input.txt")); request.method(HttpMethod.HEAD); ContentResponse response = request.send(); int responseStatus = response.getStatus(); @@ -281,12 +173,12 @@ public class JdbcLoginServiceTest { startClient(); - Request request = _client.newRequest(getBaseUrl() + "test"); + Request request = _client.newRequest(_baseUri.resolve("test")); request.method(HttpMethod.POST); request.content(new BytesContentProvider(_content.getBytes())); ContentResponse response = request.send(); assertEquals(HttpStatus.OK_200,response.getStatus()); - assertEquals(_content,_requestContent); + assertEquals(_content,_testServer.getTestHandler().getRequestContent()); } finally { @@ -302,7 +194,7 @@ public class JdbcLoginServiceTest executor.setName(executor.getName() + "-client"); _client.setExecutor(executor); AuthenticationStore authStore = _client.getAuthenticationStore(); - authStore.addAuthentication(new BasicAuthentication(URI.create(_baseUrl), __realm, "jetty", "jetty")); + authStore.addAuthentication(new BasicAuthentication(_baseUri, __realm, "jetty", "jetty")); _client.start(); } @@ -316,109 +208,13 @@ public class JdbcLoginServiceTest } } - protected static String getBasePath() - { - return _docRoot.getAbsolutePath(); - } - - protected String getBaseUrl() - { - return _baseUrl; - } - protected HttpClient getClient() { return _client; } - protected String getContent() { return _content; } - - protected static void setProtocol(String protocol) - { - _protocol = protocol; - } - - - - public static void copyStream(InputStream in, OutputStream out) - { - try - { - byte[] buffer=new byte[1024]; - int len; - while ((len=in.read(buffer))>=0) - { - out.write(buffer,0,len); - } - } - catch (EofException e) - { - System.err.println(e); - } - catch (IOException e) - { - e.printStackTrace(); - } - } - - protected static class TestHandler extends AbstractHandler { - private final String resourcePath; - - public TestHandler(String repositoryPath) { - this.resourcePath = repositoryPath; - } - - public void handle(String target, org.eclipse.jetty.server.Request baseRequest, - HttpServletRequest request, HttpServletResponse response) - throws IOException, ServletException - { - if (baseRequest.isHandled()) - { - return; - } - - OutputStream out = null; - - if (baseRequest.getMethod().equals("PUT")) - { - baseRequest.setHandled(true); - - File file = new File(resourcePath, URLDecoder.decode(request.getPathInfo())); - file.getParentFile().mkdirs(); - file.deleteOnExit(); - - out = new FileOutputStream(file); - - response.setStatus(HttpServletResponse.SC_CREATED); - } - - if (baseRequest.getMethod().equals("POST")) - { - baseRequest.setHandled(true); - out = new ByteArrayOutputStream(); - - response.setStatus(HttpServletResponse.SC_OK); - } - - if (out != null) - { - try (ServletInputStream in = request.getInputStream()) - { - copyStream(in, out); - } - finally - { - out.close(); - } - - if (!(out instanceof FileOutputStream)) - _requestContent = out.toString(); - } - - } - } } diff --git a/tests/test-loginservice/src/test/resources/jetty-logging.properties b/tests/test-loginservice/src/test/resources/jetty-logging.properties new file mode 100644 index 00000000000..adf68c7c337 --- /dev/null +++ b/tests/test-loginservice/src/test/resources/jetty-logging.properties @@ -0,0 +1,3 @@ +org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog +#org.eclipse.jetty.LEVEL=DEBUG +#org.eclipse.jetty.server.LEVEL=DEBUG