繁体   English   中英

码头-如何以编程方式在web.xml中强制实施安全约束

[英]Jetty - how to programatically enforce security-constraint in web.xml

在我们的web.xml中,我们具有以下安全约束

<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>

这很有效,除了我们需要以编程方式打开和关闭此约束之外,因此本质上需要编写一个过滤器来执行类似的操作。 这可以在码头做吗? 从本质上讲,我们需要能够基于自定义配置系统更改此功能的打开或关闭。

可以在Jetty中进行操作,但是我认为您不能在jetty.xml中有条件地进行操作。

我知道您可以通过在应用程序中嵌入Jetty并以编程方式配置和实例化您的Jetty服务器来做到这一点。 我不知道这如何适合您的部署方案,但是这里有一个嵌入式Jetty服务器的示例,该服务器在所有连接上强制执行机密。 您可以对其进行修改,以有条件地应用ConstraintSecurityHandler(内置于buildConstraintSecurityHandler的调用中),具体取决于设置自定义配置的方式。

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;
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM