Can we Reject/Accept specific endpoint on Jetty connector? - jetty

we have a connector on port 7777 and we want to reject any requests that are coming for /serverStatus on that connector?
at the same time I want to accept only /serverStatus requests on a different connector which is on port 80.

Name your ServerConnectors.
The ServerConnector on port 7777 is named "admin"
The ServerConnector on port 80 is named "normal"
Then setup the webapp for /serverStatus to have a virtualhost of #admin, and your root webapp on a virtualhost of #normal.
See Embedded-Jetty Cookbook: ConnectorSpecificContexts.java for example.
package org.eclipse.jetty.cookbook;
import org.eclipse.jetty.cookbook.handlers.HelloHandler;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
public class ConnectorSpecificContexts
{
public static void main(String[] args) throws Exception
{
Server server = new Server();
ServerConnector connectorA = new ServerConnector(server);
connectorA.setPort(8080);
connectorA.setName("connA");
ServerConnector connectorB = new ServerConnector(server);
connectorB.setPort(9090);
connectorB.setName("connB");
server.addConnector(connectorA);
server.addConnector(connectorB);
// Collection of Contexts
ContextHandlerCollection contexts = new ContextHandlerCollection();
server.setHandler(contexts);
// Hello Handler (connection A)
ContextHandler ctxHelloA = new ContextHandler();
ctxHelloA.setContextPath("/");
ctxHelloA.setHandler(new HelloHandler("Hello Connection A"));
ctxHelloA.setVirtualHosts(new String[] { "#connA" });
contexts.addHandler(ctxHelloA);
// Hello Handler (connection B)
ContextHandler ctxHelloB = new ContextHandler();
ctxHelloB.setContextPath("/");
ctxHelloB.setHandler(new HelloHandler("Greetings from Connection B"));
ctxHelloB.setVirtualHosts(new String[] { "#connB" });
contexts.addHandler(ctxHelloB);
server.start();
server.join();
}
}

Related

Embedded jetty server causing issues with UTF-8 characters

Code from servlet file
#Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
try {
Map map = req.getParameterMap();
HashMap<String, Object> paramsMap = new HashMap<String, Object>(map);
String action = HTTPUtil.getInstance().getPropertyFromHttpRequest(PARAM_ACTION, paramsMap, false);
String service = HTTPUtil.getInstance().getPropertyFromHttpRequest(PARAM_SERVICE_NAME, paramsMap, false);
String requestBody = (String)IOUtils.toString(req.getInputStream());
....
One of the field from requestBody is rendered as "Brad?" instead of "Brad's" in requestBody. Ideally "Brad's" should have been rendered. Which leads to incorrect data being stored in DB.
This is how jetty server is started :
server = new Server(new QueuedThreadPool(10));
ServerConnector connector = new ServerConnector(server);
connector.setPort(getPort());
server.addConnector(connector);
HandlerCollection handlerCollection = getHandlers();
server.setHandler(handlerCollection);
server.setStopAtShutdown(true);
server.setStopTimeout(1000);
server.start();
getHandlers() return HandlerCollection is created as:
HandlerCollection handlers = new HandlerCollection(true);
ServletContextHandler handler = new ServletContextHandler();
handler.getContextPath();
handler.addServlet(new ServletHolder(new TestServlet(), "/test");
handlers.addHandler(handler);
Jetty Version 9.2.11.v20150529
curl -X POST \
'http://master92.XYZ.com:7777/health?test=10&action=10' \
-H 'cache-control: no-cache' \
-H 'content-type: application/json; charset=utf-8' \
-d '{"name":"ABA …"}'
Request body shows up as
{"name": "ABA ?" } when dumped to logs or console
The issue was resolved with -Dfile.encoding=UTF-8 option.

How to start jetty on port 80 as root from embedded jetty?

I am trying to start the https port 443 as root then downgrade to non-root user using embedded jetty. I gone through the
https://www.eclipse.org/jetty/documentation/current/setting-port80-access.html#configuring-jetty-setuid-feature
but didn't get any solution how to do it from java program.
This is the embedded jetty code :
package com.jetty.startup;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.annotations.ServletContainerInitializersStarter;
import org.eclipse.jetty.apache.jsp.JettyJasperInitializer;
import org.eclipse.jetty.plus.annotation.ContainerInitializer;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.SslConnectionFactory;
import org.eclipse.jetty.server.SecureRequestCustomizer;
import org.apache.log4j.Logger;
import org.eclipse.jetty.setuid.*;
/**
* Handles Webapp server's serviice
*
*
*/
class MyServer {
private static Logger logger = Logger.getLogger(MyServer.class);
private static Server server;
private String jettyHome;
/**
* Creates an instance of {#link MyServer}
*
* #param jettyHome
* jetty home path
*/
public MyServer(String jettyHome) {
this.jettyHome = jettyHome;
}
/**
* Initializes Webapp server:
*
*/
public Server init() throws Exception {
server = new Server();
int httpsPort = 443;
String keyStoreFile = "/home/jetty/webserver/etc/keystore";
String keyStorePassword = "secret";
String keyManagerPassword = "secret";
String trustStorePassword = "secret";
SslContextFactory sslContextFactory = new SslContextFactory();
sslContextFactory.setKeyStorePath(keyStoreFile);
sslContextFactory.setKeyStoreType("JKS");
sslContextFactory.setKeyStorePassword(keyStorePassword);
sslContextFactory.setKeyManagerPassword(keyManagerPassword);
SetUIDListener set = new SetUIDListener();
set.setStartServerAsPrivileged(true);
set.setUsername("jetty");
set.setGroupname("jetty");
set.setUmask(002);
server.addLifeCycleListener(set);
HttpConfiguration httpConfiguration = new HttpConfiguration();
httpConfiguration.setSecurePort(httpsPort);
httpConfiguration.setSecureScheme("https");
httpConfiguration.addCustomizer(new SecureRequestCustomizer());
ServerConnector serverConnector = new ServerConnector(server,
new SslConnectionFactory(sslContextFactory, "http/1.1"),
new HttpConnectionFactory(httpConfiguration));
serverConnector.setPort(httpsPort);
server.setConnectors(new Connector[] { serverConnector });
WebAppContext myContext = new WebAppContext();
myContext.setContextPath("/myapp");
myContext.setWar(jettyHome + "/webapps/myapp/");
myContext.setDefaultsDescriptor(jettyHome + "/etc/webdefault.xml");
File overrideFile = new File(jettyHome
+ "/webapps/myapp/WEB-INF/generated-web.xml");
if (overrideFile.exists()) {
myContext.setOverrideDescriptor(jettyHome
+ "/webapps/myapp/WEB-INF/generated-web.xml");
}
server.setHandler(myContext);
JettyJasperInitializer sci = new JettyJasperInitializer();
ServletContainerInitializersStarter sciStarter =
new ServletContainerInitializersStarter(myContext);
ContainerInitializer initializer = new ContainerInitializer(sci, null);
List<ContainerInitializer> initializers = new ArrayList<>();
initializers.add(initializer);
myContext.setAttribute("org.eclipse.jetty.containerInitializers", initializers);
myContext.addBean(sciStarter, true);
ContextHandlerCollection contexts = new ContextHandlerCollection();
contexts.setHandlers(new Handler[] { myContext });
server.setHandler(contexts);
return server;
}
public static void main(String args[]) {
String jetty_home = "/home/jetty/webServer";
MyServer myServer = new MyServer(jetty_home);
try {
server = myServer.init();
server.start();
} catch (Exception excp) {
}
}
}
As for the libsetuid-linux.so I've already created the native version of it using mvn clean install from the jetty-setuid project.
If httpsPort = 2400 then this is the log file details:
Log
2016-02-11 15:36:16.413:INFO::main: Logging initialized #2424ms
2016-02-11 15:36:16.593:INFO:oejs.SetUIDListener:main: Setting umask=02
2016-02-11 15:36:16.603:INFO:oejs.SetUIDListener:main: Opened ServerConnector#b96fde{SSL,[ssl, http/1.1]}{0.0.0.0:2400}
2016-02-11 15:36:16.603:INFO:oejs.SetUIDListener:main: Setting GID=504
2016-02-11 15:36:16.676:INFO:oejs.SetUIDListener:main: Setting UID=504
2016-02-11 15:36:16.680:INFO:oejs.Server:main: jetty-9.3.7.v20160115
whereas when httpsPort = 443 this is how the log file looks:
Log
2016-02-11 15:37:35.049:INFO::main: Logging initialized #2199ms
2016-02-11 15:37:35.228:INFO:oejs.SetUIDListener:main: Setting umask=02
Nothing happens after this on the log and also the webapp isn't working.
This is ultimately a OS permissions issue, and you'll need a way to work around that.
This means any solution you come up with will also be OS specific
One example is to use the jetty-setuid-java artifact, and appropriate jetty-setuid-native library to accomplish this.
Make sure you fully understand how setuid functions on your desired OS before starting this effort
As for enabling the jetty setuid specific pieces, you can either use the XmlConfiguration to inject the appropriate lifecycle listener into your Server, or you can do it entirely in code.
See the Jetty Distribution's etc/jetty-setuid.xml for help.
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN"
"http://www.eclipse.org/jetty/configure_9_3.dtd">
<!-- ================================================================ -->
<!-- Configure the Jetty SetUIDListener -->
<!-- ================================================================ -->
<Configure id="Server" class="org.eclipse.jetty.server.Server">
<Call name="addLifeCycleListener">
<Arg>
<New class="org.eclipse.jetty.setuid.SetUIDListener">
<Set name="startServerAsPrivileged">false</Set>
<Set name="umaskOctal">002</Set>
<Set name="username">jetty</Set>
<Set name="groupname">jetty</Set>
<!-- uncomment to change the limits on number of open file descriptors for root -->
<!--
<Call name="setRLimitNoFiles">
<Arg>
<New class="org.eclipse.jetty.setuid.RLimit">
<Set name="soft">20000</Set>
<Set name="hard">40000</Set>
</New>
</Arg>
</Call>
-->
</New>
</Arg>
</Call>
</Configure>
Well finally I was able to achieve what I'd asked in the above question by creating a libsetuid-linux.so for 32-bit, the one that's supplied with jetty-9.3.7 is for 64-bit.
How I created the 32-bit libsetuid-linux.so?
This link helped http://www.eclipse.org/jetty/documentation/current/setting-port80-access.html
Point number 5 to be precise
But unfortunately the link for jetty-setuid project isn't working anymore.
Also, the sudo had to be done with sudo -E.

NoClassDefFoundError org/apache/cxf/jaxrs/client/WebClient

I am new to CXF web services. I need to write a Rest Client. I am getting
java.lang.NoClassDefFoundError: org/apache/cxf/jaxrs/client/WebClient
com.test.ws.CXFWebServiceConnector.get(CXFWebServiceConnector.java:21)
com.test.ws.SimpleServlet.doGet(SimpleServlet.java:29)
javax.servlet.http.HttpServlet.service(HttpServlet.java:620)
javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
root cause
java.lang.ClassNotFoundException: org.apache.cxf.jaxrs.client.WebClient
org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1720)
org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1571)
com.test.ws.CXFWebServiceConnector.get(CXFWebServiceConnector.java:21)
com.test.ws.SimpleServlet.doGet(SimpleServlet.java:29)
javax.servlet.http.HttpServlet.service(HttpServlet.java:620)
javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
This is not a maven project. Below jars are added in my class path. To get the NoClassDefinition Exception am I missing any other library ?
abdera-core-0.4.0-incubating.jar
abdera-extensions-main-0.4.0-incubating.jar
abdera-i18n-0.4.0-incubating.jar
abdera-parser-0.4.0-incubating.jar
axiom-api-1.2.7.jar
axiom-impl-1.2.7.jar
cxf-2.2.6.jar
geronimo-activation-1.1.jar
geronimo-annotation-1.0.jar
jaxb-api-2.1.jar
jaxb-impl-2.1.12.jar
jra-1.0-alpha-4.jar
jsr311-api-1.0.jar
neethi-2.0.4.jar
wss4j-1.5.8.jar
wstx-asl-3.2.9.jar
xml-resolver-1.2.jar
XmlSchema-1.4.5.jar
This is the way I access the Restful web service
public String get(String url) {
String response = null;
WebClient client = WebClient.create(url);
client.accept(MediaType.APPLICATION_JSON);
HTTPConduit conduit = WebClient.getConfig(client).getHttpConduit();
HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy();
httpClientPolicy.setAllowChunking(false);
conduit.setClient(httpClientPolicy);
TLSClientParameters clientParameters = new TLSClientParameters();
clientParameters.setDisableCNCheck(true);
clientParameters.setSecureSocketProtocol("TLS");
conduit.setTlsClientParameters(clientParameters);
try {
response = client.get(String.class);
} finally {
if (client != null) {
client.reset();
}
}
return response;
}
WebClient is part of cxf-rt-frontend-jaxrs.jar. You do not have cxf JAXRS related jars I guess.
Use the below command in your project root to detect which dependencies are required:
mvn dependency:tree -Dincludes=org.apache.cxf

Getting SSLHandshakeException while testing SOAP web service

I am trying to connect a SOAP web service using apache http client. It is secured one (identified by https). I have added code for keystore file also.
Here is the code:
CloseableHttpClient httpclient = null;
try {
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
FileInputStream instream = new FileInputStream(new File("C:\\SOAP\\qa.keystore"));
try {
trustStore.load(instream, "test1234".toCharArray());
}
catch(Exception e){
e.printStackTrace();
}
finally {
instream.close();
}
SSLContext sslcontext = SSLContexts.custom()
.loadTrustMaterial(trustStore, new TrustSelfSignedStrategy())
.build();
httpclient = HttpClients.custom()
.setSslcontext(sslcontext)
.build();
HttpPost httppost = new HttpPost("https://dev env hostname:7443/wsx/services/reiveFile_WS_VT_SECURED_INBOUND");
FileBody bin = new FileBody(new File("C:\\Payment Check8jan3.dat"));
StringBody fileName = new StringBody("Payment Check8jan3.dat", ContentType.TEXT_PLAIN);
StringBody fileType = new StringBody("111", ContentType.TEXT_PLAIN);
StringBody messageId = new StringBody("3454", ContentType.TEXT_PLAIN);
StringBody senderId = new StringBody("ekrjekrj", ContentType.TEXT_PLAIN);
StringBody checksum = new StringBody("b2ee8af554ab6933085d341b71765bc8", ContentType.TEXT_PLAIN);
StringBody timestamp = new StringBody("3434", ContentType.TEXT_PLAIN);
StringBody transportServiceVersion = new StringBody("4343", ContentType.TEXT_PLAIN);
HttpEntity reqEntity = MultipartEntityBuilder.create()
.addPart("FileName", fileName)
.addPart("FileType", fileType)
.addPart("messageId", messageId)
.addPart("senderId", senderId)
.addPart("checksum", checksum)
.addPart("timestamp", timestamp)
.addPart("transportServiceVersion", transportServiceVersion)
.addPart("payload", bin)
.build();
httppost.setEntity(reqEntity);
System.out.println("executing request " + httppost.getRequestLine());
CloseableHttpResponse response = httpclient.execute(httppost);
try {
System.out.println("----------------------------------------");
System.out.println(response.getStatusLine());
HttpEntity resEntity = response.getEntity();
if (resEntity != null) {
System.out.println("Response content length: " + resEntity.getContentLength());
}
EntityUtils.consume(resEntity);
} finally {
response.close();
}
} finally {
httpclient.close();
}
I am getting the below exception :
Exception in thread "main" javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake
at sun.security.ssl.SSLSocketImpl.readRecord(Unknown Source)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source)
at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source)
at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source)
at org.apache.http.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:275)
at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:254)
at org.apache.http.impl.conn.HttpClientConnectionOperator.connect(HttpClientConnectionOperator.java:117)
at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:314)
at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:363)
at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:219)
at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:195)
at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:86)
at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:108)
at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:186)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:106)
at Test.test(Test.java:113)
at Test.main(Test.java:229)
Caused by: java.io.EOFException: SSL peer shut down incorrectly
at sun.security.ssl.InputRecord.read(Unknown Source)
... 18 more
Edit:
As suggested in one of the answer, I imported certificate into cacerts file also. But still getting the same exception.
Please suggest.
This is just a guess but given that the SSL handshake fails in its initial phase I would suspect a protocol version incompatibility. Try forcing the use of an older protocol version such as SSLv3 or SSLv2 and see if that makes any difference.
SSLContext sslcontext = SSLContexts.custom()
.loadTrustMaterial(trustStore)
.build();
SSLConnectionSocketFactory sslcsf = new SSLConnectionSocketFactory(
sslcontext, new String[] {"SSLv3"}, null, null);
CloseableHttpClient client = HttpClients.custom()
.setSSLSocketFactory(sslcsf)
.build();
In general when dealing with SSL issues of any sort a debug log of the SSL initial handshake is usually enough to pinpoint the cause of the problem. See this troubleshooting guide for details
Try importing certificates into cacerts file or create a new one, also point the same to your server where webservice is hosted/consumed.
Also check properly, if complete certificate chain is imported into truststore or not.
The same can be achieved programmatically or through importing into cacerts.
Better way to to import into trusstore, also check for public and private keys if imported properly.

How to use NSS with Jetty?

I am trying to setup Jetty to use NSS as its cryptographic engine. I have gotten it to the point where the server starts BUT any client that tries to connect seems to hang in the browser.
The setup process / code I am following is as follows (32-bit Windows 1.6 JVM).
NSS Database Creation
modutil.exe -create -dbdir C:\nssdb
modutil.exe -create -fips true -dbdir C:\nssdb
modutil.exe -create -changepw "NSS FIPS 140-2 Certificate DB" -dbdir C:\nssdb
Load NSS into Java
String config = "name = NSS\n";
config += "nssLibraryDirectory = C:\\nss\\lib\n";
config += "nssSecmodDirectory = C:\\nssdb\n";
config += "nssDbMode = readWrite\n";
config += "nssModule = fips";
InputStream stream = new ByteArrayInputStream(config.getBytes("UTF-8"));
Provider nss = new sun.security.pkcs11.SunPKCS11(stream);
Security.addProvider(nss);
int sunJssePosition = -1;
int currentIndex = 0;
for (Provider provider : Security.getProviders()) {
if ("SunJSSE".equals(provider.getName())) {
sunJssePosition = currentIndex + 1;
break;
}
currentIndex++;
}
Security.removeProvider("SunJSSE");
Provider sunJsse = new com.sun.net.ssl.internal.ssl.Provider(nss);
if (sunJssePosition == -1) {
Security.addProvider(sunJsse);
} else {
Security.insertProviderAt(sunJsse, sunJssePosition);
}
NSS Self Sign Certificate Generation
C:\nss\bin\certutil.exe -S -n 127.0.0.1 -x -t "u,u,u" -s "CN=127.0.0.1, OU=Foo, O=Bar, L=City, ST=NY, C=US" -m 25001 -d C:\nssdb
Jetty Startup
KeyStore ks = KeyStore.getInstance("PKCS11");
ks.load(null, "SuperSecret");
//Start setting up Jetty
Server server = new Server();
SslContextFactory sslContextFactory = new SslContextFactory();
//sslContextFactory.setKeyStoreProvider("SunPKCS11-NSS");
sslContextFactory.setKeyStore(ks);
//sslContextFactory.setKeyStorePassword(new String("SuperSecret"));
SslSelectChannelConnector sslConnector = new SslSelectChannelConnector(sslContextFactory);
sslConnector.setPort(443);
server.addConnector(sslConnector);
WebAppContext context = new WebAppContext();
//Blah Blah Blah, setup Jetty
server.setHandler(context);
server.start();
server.join();
Any ideas?
Edit: This seems extremely odd but I can access the server using Internet Explorer just fine. Firefox seems to be the one having an issue.
I have solved the issue. It turns out there are severe bugs in the Java 6 SSL implementation. The solution? Switch to Java 7!