I have embedded Jetty server in my Java code. I am loading a SSL certificate by using SslContextFactory class. My problem is when Jetty server starts that time .jks file is not present at the mentioned file path because it is generated dynamically and stores in the path. As .jks file is not present so server is not starting and giving NullPointerException. I will use sslContextFactory.reload() when certificate available on path but I am not sure how to deal with NullPointerException at the starting time.
Is there way to tell Jetty start without certificate and when sslContextFactory.reload() reloads the certificate.
Update
Jetty Version : 9.4.26.v20200117
I am using below code to load certificate.
private final static String KEYSTORE_LOCATION = "/home/myproject/keystore.jks";
SslContextFactory sslContextFactory = new SslContextFactory();
sslContextFactory.setKeyStorePath(getKeystoreLocation());
sslContextFactory.setKeyStorePassword("temp");
sslContextFactory.setKeyManagerPassword("temp");
private static String getKeystoreLocation() throws MalformedURLException {
File file = new File(KEYSTORE_LOCATION);
URL url = file.toURI().toURL();
return url.toExternalForm();
}
I am getting NullPointerException for file. Can you please let me know what missing here?
Use Jetty 9.4.46 (or newer).
Jetty 9.4.26 is subject to a few security issues now - see https://www.eclipse.org/jetty/security_reports.php for details
Is this SslContextFactory for Server or for Client use?
Server uses SslContextFactory.Server, and client uses SslContextFactory.Client implementations. (your old version of Jetty might not have this distinction, which was a source of a few issues in the past)
The configured keystore/truststore file(s) needs to exist once you start Jetty.
Even if that keystore/truststore file is a dummy/empty one, it needs to exist.
Once you start, you can replace the keystore/truststore file(s) and the SslContextFactory will detect the changed file and reload the SslContextFactory.
Related
I'm banging my head against the wall on this. I wrote a tiny embedded jetty server (jetty 9.4.18, jersey 1.19.4) and I cannot for the life of me get it to respect the context path and my REST services deployed.
I tried setContextPath, but that never worked on ServletContextHandler, so I went with WebAppContext.
This is about as simple as I can get it:
Server jettyServer = new Server(9999);
// set up the web app
WebAppContext webapp = new WebAppContext();
webapp.setContextPath("/app/");
webapp.setResourceBase("web");
jettyServer.setHandler(webapp);
// add REST service
ServletHolder jerseyServlet = webapp.addServlet(ServletContainer.class, "/service/*");
final ResourceConfig resourceConfig = new ResourceConfig(RestService.class);
resourceConfig.register(MultiPartFeature.class);
jerseyServlet.setInitParameter("jersey.config.server.provider.packages", "org.futureboy.app.server.rest");
try {
jettyServer.start();
jettyServer.join();
} catch (Exception e) {
e.printStackTrace();
//jettyServer.stop();
jettyServer.destroy();
}
The static HTML files are served up in the web directory, and this works fine if I keep this line as follows:
ServletHolder jerseyServlet = webapp.addServlet(ServletContainer.class, "/service/*");
However this means the REST service (which operates under /app/service) does not work. If I swap this line out:
ServletHolder jerseyServlet = webapp.addServlet(ServletContainer.class, "/*");
Then the REST service works fine, but now the static HTML content does NOT work fine. So I either get a working static HTML service on /app/ or a working REST service underneath /app/service, but I can't have both. What am I doing wrong? The RestService.java file starts like:
#Path("/service")
public class RestService {
Any help would be appreciated, for I feel I am stuck on the one-yard line here.
Why do you want Jersey to serve static content?
That's not the role of a JAX-B server.
What do do ...
Switch from WebAppContext to ServletContextHandler (you don't need the overhead of WebAppContext or any of the bytecode scanning or annotation scanning deployment techniques that a full blown WebAppContext brings to the table.
Prevent Jersey from serving static content.
Setup a proper ResourceBase - use a fully qualified path or URI (no relative paths, no partial URIs)
Add a DefaultServlet on the default url-pattern "/" named "default".
Which these changes Jetty will serve static content, from your Resource Base.
Some prior answers/examples of the Jetty side configuration and DefaultServlet usage:
Deploying Jetty server via .jar. Why can't I access the index?
How to get embedded Jetty serving html files from a Jar, not a War
Serving static files from alternate path in embedded Jetty
What is difference between ServletContextHandler.setResourceBase and ResourceHandler.setResourceBase when using Jetty embedded container?
Jetty: default servlet context path
Display static HTML file from resources folder in Jetty Serverlet doGet method
And there's many many answers on how to configure Jersey to not serve static content.
One my favs is the solution provided at ...
Servlet for serving static content
I am trying to connect to a Apache Ignite Server from a Spring Boot Application.
Example code:
ClientConfiguration cfg = new ClientConfiguration().setAddresses("127.0.0.1:10800");
try (IgniteClient client = Ignition.startClient(cfg)) {
Object cachedName = client.query(
new SqlFieldsQuery("SELECT name from Person WHERE id=?").setArgs("foo").setSchema("PUBLIC")
).getAll().iterator().next().iterator().next();
}
I get this error:
Caused by: class org.apache.ignite.IgniteCheckedException: Remote node
has peer class loading enabled flag different from local
[locId8=459833a1, locPeerClassLoading=true, rmtId8=83ea88ca,
rmtPeerClassLoading=false,
rmtAddrs=[ignite-0.ignite.default.svc.cluster.local/0:0:0:0:0:0:0:1%lo,
/10.4.2.49, /127.0.0.1], rmtNode=ClusterNode
[id=83ea88ca-da77-4887-9357-267ac7397767, order=1,
addr=[0:0:0:0:0:0:0:1%lo, 10.x.x.x, 127.0.0.1], daemon=false]]
So the PeerClassLoading needs to be deactivated in my Java code. How can I do that?
As noted in the comments, the error is from a thick client (or another server) connecting to the cluster but the code is from a thin client.
If you’re just reading/writing data and don’t need to execute code, the thin client is a perfectly good option.
To use a thick client, you need to make sure both the thick client and server have the same peer-class loading configuration. That would be either:
<property name=“peerClassLoadingEnabled” value=“false” />
in your Spring configuration file. Or:
IgniteConfiguration cfg = new IgniteConfiguration()
...
.setPeerClassLoadingEnabled(false);
(I’ve used false here as that’s your current server configuration. Having said that, you probably want it to be switched on.)
I have a web app running in Tomcat correctly that I want to run on the new OpenLiberty server, the app is starting correctly inside OpenLiberty but at the moment of the database connection initiation is throwing the following exception:
[Default Executor-thread-15] 2018-03-15 15:02:30 ERROR TomcatConnectionManager:41 - Loading jdbc/mysql/myaap failure
javax.naming.NameNotFoundException: java:/comp/env
at com.ibm.ws.jndi.url.contexts.javacolon.internal.JavaURLName.<init>(JavaURLName.java:83)
at com.ibm.ws.jndi.url.contexts.javacolon.internal.JavaURLNameParser.parse(JavaURLNameParser.java:39)
at com.ibm.ws.jndi.url.contexts.javacolon.internal.JavaURLNameParser.parse(JavaURLNameParser.java:60)
at com.ibm.ws.jndi.url.contexts.javacolon.internal.JavaURLContext$NameUtil.<init>(JavaURLContext.java:474)
at com.ibm.ws.jndi.url.contexts.javacolon.internal.JavaURLContext.lookup(JavaURLContext.java:321)
at com.ibm.ws.jndi.url.contexts.javacolon.internal.JavaURLContext.lookup(JavaURLContext.java:370)
at org.apache.aries.jndi.DelegateContext.lookup(DelegateContext.java:161)
The above exception is thrown during the lookup phase:
Context initContext = new InitialContext();
Context envContext = (Context) initContext.lookup("java:/comp/env");
Is there any way to make it work on OpenLiberty doing less changes possible?
On OpenLiberty the equivalent lookup would look like this:
Context initContext = new InitialContext();
Context envContext = (Context) initContext.lookup("java:comp/env");
The key is that you need to use java:comp/... instead of java:/comp/...
The reason why Tomcat is different than Liberty is because Tomcat is just a servlet container and Liberty conforms to the full Java EE specification.
According to section EE.5.2.2 of the Java EE 7 spec:
The application component’s naming environment is composed of four logical
namespaces, representing naming environments with different scopes. The four
namespaces are:
java:comp – Names in this namespace are per-component (for example, per enterprise
bean). Except for components in a web module, each component gets
its own java:comp namespace, not shared with any other component. Components
in a web module do not have their own private component namespace.
See note below.
java:module – Names in this namespace are shared by all components in a
module (for example, all enterprise beans in a single EJB module, or all components
in a web module).
java:app – Names in this namespace are shared by all components in all modules
in a single application, where “single application” means a single deployment
unit, such as a single ear file, a single module deployed standalone, etc.
For example, a war file and an EJB jar file in the same ear file would both have
access to resources in the java:app namespace.
java:global – Names in this namespace are shared by all applications deployed
in an application server instance. Note that an application server instance
may represent a single server, a cluster of servers, an administrative
domain containing many servers, or even more. The scope of an application
server instance is product-dependent, but it must be possible to deploy multiple
applications to a single application server instance.
Had a similar problem going between WebSphere and Tomcat. I'm developing and testing on a Tomcat server and using utilities I can't change that handle the DB connection to our DB2. On WebSphere it uses a constant set to "jdbc/COMPDB2" to retrieve the DataSource when I configure Tomcat and my Web.xml file it resolves to "java:comp/env/jdbc/SFCCDB2"
My work around for on local work space it to add a listener to copy the resource to the level in the InitialContext. I'm not very experienced with the server side of things but this is working so far using TomEE 7.0.81.
InitialContext ctx = new InitialContext();
DataSource ds = (DataSource) ctx.lookup("java:comp/env/jdbc/SFCCDB2");
javax.naming.Context envCtx = (javax.naming.Context) ctx.lookup("java:comp/env");
try{
/*
Added this because after redeploying code to the server it would error
connecting to the DB with an SQLException Datasource is closed
*/
DataSource dataSource = (DataSource) ctx.lookup("jdbc/COMPDB2");
ctx.destroySubcontext("jdbc");
} catch (NamingException e){
//Doesn't exist; safe to just add
}
ctx.createSubcontext("jdbc");
ctx.bind("jdbc/COMPDB2", ds);
ctx.close();
I am working on a Java EE 7 application. I am using Payara micro to deploy my WAR files. Now, I need JDBC connectivity in my application, but I need to keep the database IP/username/password somewhere I can change later on, without re-uploading and deploying WAR file again.
Could anybody please tell me how can I achieve this?
EDIT:
I came accross a solution to that on SO:
https://stackoverflow.com/a/6296375/1931698
But, I am looking for a solution without all that plumbing. Inheriting DataSource just to have connection info in some external file looks like overkill.
EDIT:
Also, it would be really helpful if I can just provide a configuration panel to the user, where he / she can enter JDBC connection info. Is there a way to change that info at runtime (effectively discarding existing connection pool and creating a new one)?
Payara Micro should allow system property replacement in Datasource definitions using the syntax ${system.property.name} you can use that to define the database user name and password as well as the connect strings.
There is also environment variable support in 171.1 onwards using the syntax ${ENV=env.name} where env.name is the environment variable name.
Make use of java.utils.Properties with a seperate myproperties.properties file in your src folder (in classpath).
Properties prop = null;
try {
prop = new Properties();
InputStream inputStream = getClass().getClassLoader()
.getResourceAsStream("myProperty.properties");
if (inputStream != null) {
prop.load(inputStream);
}
} catch (IOException e) {
errorLog.error("Property file not found in classpath:
ClientChecking Class.");
}
String userName = prop.getProperty("USERNAME");
myproperties.properties file must contain:
USERNAME=user123
If you are using Apache tomcat for hosting, then you can find and edit the propertyfile from path WebContent(Root dir)/WEB-INF/classes/
I'm trying to set up Spring Security to work with Spring Boot's embedded Tomcat instance. There are quite a few basic samples that do this but I'm stuck where they leave off -- they do basic authentication over HTTP (not HTTPS).
I could probably make it work if I had access to the Tomcat configuration files (server.xml) but since Spring Boot uses an embedded Tomcat instance (which is otherwise a huge convenience), I dont have access to the Tomcat configuration files (at least, not to my knowledge).
There may be an application.properties setting for this but I haven't been able to track it down. I've seen references to a server.contextPath field in application.properties that I suspect may have something to do with replacement Tomcat config files. Even if it is related, I wouldn't know where to begin anyway -- all of the Tomcat SSL instructions I've seen start with editing an existing server.xml file, not building one from scratch.
Can this be done with Spring Boot (either by somehow specifying a snippet of server.xml or through other means)? If not, what would be the simplest way to do this? I understand that I may need to exclude the Tomcat component of Spring Boot but I'd prefer to avoid that if possible.
Starting with Spring Boot 1.2, you can configure SSL using application.properties or application.yml. Here's an example for application.properties:
server.port = 8443
server.ssl.key-store = classpath:keystore.jks
server.ssl.key-store-password = secret
server.ssl.key-password = another-secret
Same thing with application.yml:
server:
port: 8443
ssl:
key-store: classpath:keystore.jks
key-store-password: secret
key-password: another-secret
Here's a link to the current reference documentation.
For external keystores, prefix with "file:"
server.ssl.key-store=file:config/keystore
It turns out that there is a way to do this, although I'm not sure I've found the 'proper' way since this required hours of reading source code from multiple projects. In other words, this might be a lot of dumb work (but it works).
First, there is no way to get at the server.xml in the embedded Tomcat, either to augment it or replace it. This must be done programmatically.
Second, the 'require_https' setting doesn't help since you can't set cert info that way. It does set up forwarding from http to https, but it doesn't give you a way to make https work so the forwarding isnt helpful. However, use it with the stuff below, which does make https work.
To begin, you need to provide an EmbeddedServletContainerFactory as explained in the Embedded Servlet Container Support docs. The docs are for Java but the Groovy would look pretty much the same. Note that I haven't been able to get it to recognize the #Value annotation used in their example but its not needed. For groovy, simply put this in a new .groovy file and include that file on the command line when you launch spring boot.
Now, the instructions say that you can customize the TomcatEmbeddedServletContainerFactory class that you created in that code so that you can alter web.xml behavior, and this is true, but for our purposes its important to know that you can also use it to tailor server.xml behavior. Indeed, reading the source for the class and comparing it with the Embedded Tomcat docs, you see that this is the only place to do that. The interesting function is TomcatEmbeddedServletContainerFactory.addConnectorCustomizers(), which may not look like much from the Javadocs but actually gives you the Embedded Tomcat object to customize yourself. Simply pass your own implementation of TomcatConnectorCustomizer and set the things you want on the given Connector in the void customize(Connector con) function. Now, there are about a billion things you can do with the Connector and I couldn't find useful docs for it but the createConnector() function in this this guys personal Spring-embedded-Tomcat project is a very practical guide. My implementation ended up looking like this:
package com.deepdownstudios.server
import org.springframework.boot.context.embedded.tomcat.TomcatConnectorCustomizer
import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory
import org.apache.catalina.connector.Connector;
import org.apache.coyote.http11.Http11NioProtocol;
import org.springframework.boot.*
import org.springframework.stereotype.*
#Configuration
class MyConfiguration {
#Bean
public EmbeddedServletContainerFactory servletContainer() {
final int port = 8443;
final String keystoreFile = "/path/to/keystore"
final String keystorePass = "keystore-password"
final String keystoreType = "pkcs12"
final String keystoreProvider = "SunJSSE"
final String keystoreAlias = "tomcat"
TomcatEmbeddedServletContainerFactory factory =
new TomcatEmbeddedServletContainerFactory(this.port);
factory.addConnectorCustomizers( new TomcatConnectorCustomizer() {
void customize(Connector con) {
Http11NioProtocol proto = (Http11NioProtocol) con.getProtocolHandler();
proto.setSSLEnabled(true);
con.setScheme("https");
con.setSecure(true);
proto.setKeystoreFile(keystoreFile);
proto.setKeystorePass(keystorePass);
proto.setKeystoreType(keystoreType);
proto.setProperty("keystoreProvider", keystoreProvider);
proto.setKeyAlias(keystoreAlias);
}
});
return factory;
}
}
The Autowiring will pick up this implementation an run with it. Once I fixed my busted keystore file (make sure you call keytool with -storetype pkcs12, not -storepass pkcs12 as reported elsewhere), this worked. Also, it would be far better to provide the parameters (port, password, etc) as configuration settings for testing and such... I'm sure its possible if you can get the #Value annotation to work with Groovy.
If you don't want to implement your connector customizer, you can build and import the library (https://github.com/ycavatars/spring-boot-https-kit) which provides predefined connector customizer. According to the README, you only have to create your keystore, configure connector.https.*, import the library and add #ComponentScan("org.ycavatars.sboot.kit"). Then you'll have HTTPS connection.
And here's an example of the customizer implemented in Groovy:
https://github.com/UniconLabs/orville/blob/master/web/src/main/groovy/org/apereo/openregistry/config/TomcatSslConfiguration.groovy