问题描述
在我们的web.xml中,我们有以下安全约束
In our web.xml we had the following security-constraint
<security-constraint>
<web-resource-collection>
<web-resource-name>Everything on the app</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
除非我们需要以编程方式打开和关闭此约束,否则这样做很有效,所以写一个过滤器来做基本上需要类似的东西。这可能在码头吗?基本上我们需要能够根据自定义配置系统打开或关闭它。
This works great except we need to programatically turn this constraint on and off, so writing a filter to do something similar is essentially needed. Is this possible to do in jetty? Essentially we need to be able to change if this is turned on or off based on a custom configuration system.
推荐答案
这是可能的在Jetty中做但我认为你不能在jetty.xml中有条件地做到这一点。
It is possible to do in Jetty but I don't think you can do it conditionally within jetty.xml.
我知道你可以通过在你的应用程序中嵌入Jetty并以编程方式配置和实例化你的Jetty服务器来实现。我不知道这是如何适合您的部署方案的,但这里是一个嵌入式Jetty服务器的例子,它在所有连接上强制使用CONFIDENTIAL。您可以修改它以有条件地应用ConstraintSecurityHandler(内置调用buildConstraintSecurityHandler),具体取决于您的自定义配置的设置方式。
I know you can do it by embedding Jetty in your application and programmatically configuring and instantiating your Jetty server. I don't know how this fits into your deployment scenario but here's an example of an embedded Jetty server that enforces CONFIDENTIAL on all connections. You could modify it to conditionally apply the ConstraintSecurityHandler (built in call to buildConstraintSecurityHandler) depending on how your custom configuration is set.
package com.example.webapp;
import com.example.webapp.guice.ProdModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import org.apache.commons.codec.binary.Base64;
import org.eclipse.jetty.security.ConstraintMapping;
import org.eclipse.jetty.security.ConstraintSecurityHandler;
import org.eclipse.jetty.server.*;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.HandlerList;
import org.eclipse.jetty.server.handler.ResourceHandler;
import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.util.security.Constraint;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.glassfish.jersey.servlet.ServletContainer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.security.*;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Collections;
import java.util.Properties;
public class EmbeddedServer {
static Server server = null;
private final static String componentUUID = "f2dsfb1d-9e7a-4c9f-984e-ee5sdfa68d60";
private static String getHandlerPackages() {
return "com.example";
}
private static Properties properties;
final static Logger log = LoggerFactory.getLogger(EmbeddedServer.class);
static PrivateKey createPrivateKey(String keyFileName) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
// see https://www.openssl.org/docs/HOWTO/certificates.txt
PrivateKey privateKey;
FileInputStream fis = new FileInputStream(keyFileName);
InputStreamReader isr = new InputStreamReader(fis);
BufferedReader br = new BufferedReader(isr);
// TODO Handle DER format private keys
String line;
StringBuilder sb = new StringBuilder();
while ((line = br.readLine()) != null) {
sb.append(line);
}
String pemString = sb.toString();
pemString = pemString.replace("-----BEGIN PRIVATE KEY-----", "");
pemString = pemString.replace("-----END PRIVATE KEY-----", "");
Base64 decoder = new Base64();
byte[] encoded = decoder.decode(pemString);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded);
KeyFactory kf = KeyFactory.getInstance("RSA");
privateKey = kf.generatePrivate(keySpec);
return privateKey;
}
private static KeyStore createJavaKeyStore(String certFileName, String keyFileName) throws IOException, CertificateException, KeyStoreException, NoSuchAlgorithmException, InvalidKeySpecException {
// see https://www.openssl.org/docs/HOWTO/keys.txt
KeyStore ks = KeyStore.getInstance("JKS");
FileInputStream fis = new FileInputStream(certFileName);
BufferedInputStream bis = new BufferedInputStream(fis);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
Certificate cert = null;
// load the x.509 certificate
while (bis.available() > 0) {
cert = cf.generateCertificate(bis);
}
bis.close();
fis.close();
ks.load(null, null);
ks.setKeyEntry("keyentry,", createPrivateKey(keyFileName), componentUUID.toCharArray(), new Certificate[]{cert});
return ks;
}
public static Server createServerWithConnectors() throws IOException, InvalidKeySpecException, CertificateException, NoSuchAlgorithmException, KeyStoreException {
Server server = new Server();
SslContextFactory sslContextFactory;
KeyStore ks = createJavaKeyStore("ssl/cacertpemkey.pem", "ssl/privkey.pem");
sslContextFactory = new SslContextFactory();
sslContextFactory.setKeyStore(ks);
sslContextFactory.setKeyStorePassword(componentUUID);
// HTTP Configuration
// HttpConfiguration is a collection of configuration information appropriate for http and https. The default
// scheme for http is <code>http</code> of course, as the default for secured http is <code>https</code> but
// we show setting the scheme to show it can be done. The port for secured communication is also set here.
HttpConfiguration http_config = new HttpConfiguration();
http_config.setSecureScheme("https");
http_config.setSecurePort(getPort(true));
http_config.setOutputBufferSize(32768);
// HTTP connector
// The first server connector we create is the one for http, passing in the http configuration we configured
// above so it can get things like the output buffer size, etc. We also set the port (8080) and configure an
// idle timeout.
ServerConnector http = new ServerConnector(server, new HttpConnectionFactory(http_config));
http.setPort(getPort(false));
http.setIdleTimeout(30000);
// HTTPS Configuration
// A new HttpConfiguration object is needed for the next connector and you can pass the old one as an
// argument to effectively clone the contents. On this HttpConfiguration object we add a
// SecureRequestCustomizer which is how a new connector is able to resolve the https connection before
// handing control over to the Jetty Server.
HttpConfiguration https_config = new HttpConfiguration(http_config);
https_config.addCustomizer(new SecureRequestCustomizer());
// HTTPS connector
// We create a second ServerConnector, passing in the http configuration we just made along with the
// previously created ssl context factory. Next we set the port and a longer idle timeout.
ServerConnector https = new ServerConnector(server,
new SslConnectionFactory(sslContextFactory, "http/1.1"),
new HttpConnectionFactory(https_config));
https.setPort(getPort(true));
https.setIdleTimeout(500000);
// Here you see the server having multiple connectors registered with it, now requests can flow into the server
// from both http and https urls to their respective ports and be processed accordingly by jetty. A simple
// handler is also registered with the server so the example has something to pass requests off to.
// Set the connectors
server.setConnectors(new Connector[]{http, https});
return server;
}
public static int getPort(boolean secure) {
String s;
if (secure)
s = properties.getProperty("secure.port", "8443");
else
s = properties.getProperty("port", "8080");
return Integer.parseInt(s);
}
public static void stopServer()
{
if (server != null) {
try {
server.stop();
} catch (Exception e) {
log.info("Exception in stopServer", e);
}
}
}
public static Server startServerIfNeeded()
{
if (server == null) {
try {
server = createServerWithConnectors();
HandlerList handlers = buildServerHandlers();
server.setHandler(handlers);
server.start();
server.join();
} catch (Exception e) {
log.info("Exception in startServerIfNeeded", e);
}
}
return server;
}
public static void main(String [] args)
{
log.info("Embedded server startup");
properties = Util.getProperties("embeddedserver.properties");
startServerIfNeeded();
}
private static HandlerList buildServerHandlers() {
HandlerList handlers = new HandlerList();
ConstraintSecurityHandler securityHandler = buildConstraintSecurityHandler();
ServletContextHandler servletContexttHandler = buildJerseyServletHandler();
securityHandler.setHandler(servletContexttHandler);
handlers.addHandler(securityHandler);
securityHandler = buildConstraintSecurityHandler();
ContextHandler ch = buildStaticResourceHandler();
securityHandler.setHandler(ch);
handlers.addHandler(securityHandler);
return handlers;
}
private static ServletContextHandler buildJerseyServletHandler() {
ServletContextHandler servletContextHandler = new ServletContextHandler(
ServletContextHandler.SESSIONS);
servletContextHandler.setContextPath("/api");
servletContextHandler.setErrorHandler(new MyServletContextErrorHandler());
servletContextHandler.addEventListener(new MyServletContextListener());
servletContextHandler.setAttribute(Injector.class.getName(), Guice.createInjector(new ProdModule()));
servletContextHandler.addFilter(new FilterHolder(new LoggingFilter()),"/*",null);
ServletHolder servletHolder = new ServletHolder(new ServletContainer());
String packageList = getHandlerPackages();
servletHolder.setInitParameter(
"jersey.config.server.provider.packages", packageList);
servletContextHandler.addServlet(servletHolder, "/*");
return servletContextHandler;
}
private static ContextHandler buildStaticResourceHandler() {
// if you want the static content to serve off a url like
// localhost:8080/files/.... then put 'files' in the constructor
// to the ContextHandler
ContextHandler ch = new ContextHandler("/");
ResourceHandler rh = new ResourceHandler();
rh.setWelcomeFiles(new String[]{"index.html"});
rh.setResourceBase(properties.getProperty("static.resource.base"));
ch.setHandler(rh);
return ch;
}
private static ConstraintSecurityHandler buildConstraintSecurityHandler() {
// this configures jetty to require HTTPS for all requests
Constraint constraint = new Constraint();
constraint.setDataConstraint(Constraint.DC_CONFIDENTIAL);
ConstraintMapping mapping = new ConstraintMapping();
mapping.setPathSpec("/*");
mapping.setConstraint(constraint);
ConstraintSecurityHandler security = new ConstraintSecurityHandler();
security.setConstraintMappings(Collections.singletonList(mapping));
return security;
}
}
这篇关于Jetty - 如何在web.xml中以编程方式强制执行安全性约束的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!