是否将Tomcat服务器上托管的Jenkins的HTTP重定向到HTTPS?

92vpleto  于 2022-11-13  发布在  Jenkins
关注(0)|答案(2)|浏览(159)

我在tomcat9(Linux)上部署了jenkins.war,并将其配置为http和https。
server.xml上的配置

<Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
           redirectPort="8443" />
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
           maxThreads="150" SSLEnabled="true">
    <SSLHostConfig>
            <Certificate certificateKeystoreFile="conf/ssl/test.keystore"
                     type="RSA" certificateKeystorePassword="changeit"/>
    </SSLHostConfig>
</Connector>

web.xml上的配置

<security-constraint>
        <web-resource-collection>
            <web-resource-name>HTTPSOnly</web-resource-name>
            <url-pattern>/*</url-pattern>
        </web-resource-collection>
        <user-data-constraint>
            <transport-guarantee>CONFIDENTIAL</transport-guarantee>
        </user-data-constraint>
    </security-constraint>

当jenkins没有托管的时候,我可以用上面的tomcat配置将http重定向到https。但是在部署了jenkins.war之后,将http重定向到https就不起作用了。
对于jenkins,将http重定向到https还需要进行其他配置更改吗?

3bygqnnd

3bygqnnd1#

如果您在'$ Catalina _BASE/conf/web.xml'中添加了一个安全约束,则该约束将使用Servlet规范中定义的约束组合规则与Web应用程序中定义的任何约束合并。
默认情况下,Jenkins定义了以下安全约束:

<security-constraint>
    <web-resource-collection>
      <web-resource-name>other</web-resource-name>
      <url-pattern>/*</url-pattern>
    </web-resource-collection>
    <!-- no security constraint --> 
  </security-constraint>

Servlet规范中的相关规则是:

The combination of user-data-constraints that apply to a common url-
pattern and http-method shall yield the union of connection types accepted by
the individual constraints as acceptable connection types. A security constraint that
does not contain a user-data-constraint shall combine with other user-data-
constraint to cause the unprotected connection type to be an accepted connection
type.

因此,Jenkins规则与您的规则相结合,结果是允许无保护的(http)连接。
可能的解决方案包括:

  • 从打包在jenkins.war中的web.xml文件中删除安全约束
  • 编辑jenkins.war中打包的web.xml文件中的安全约束
  • 部署自定义Valve或Filter以强制执行重定向
9q78igpj

9q78igpj2#

根据answer from Mark Thomas中的注解,我尝试了两种不同的方法,这两种方法都对我有效。
这两种方法还需要您在问题中描述的更改。

接近一号

编辑Jenkins WAR中的安全约束。
为此,我让Tomcat分解webapps目录中的WAR,然后编辑webapps/jenkins/WEB-INF/web.xml目录中的文件。

<!-- commented out this part...
  <security-constraint>
    <web-resource-collection>
      <web-resource-name>other</web-resource-name>
      <url-pattern>/*</url-pattern>
    </web-resource-collection>
  -->   
    <!-- no security constraint --> 
  <!-- ...and this part </security-constraint> -->

接近二号

我创建了一个Tomcat valve,并将其创建为JAR文件,然后将其放置在Tomcat的主lib目录中。
我在Tomcat中添加了一个阀门元件,以激活阀门。
具体操作步骤:
1.我使用的是Jenkins LTS(长期支持)的最新版本-版本2.346.3。因为此版本的Jenkins不支持jakarta包,所以我将其安装在Tomcat 9上(用于javax包)。
1.我创建了一个标准的Java库项目,它被打包到一个JAR中(而不是WAR)。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.ajames.tomcathttpsvalve</groupId>
    <artifactId>TomcatHttpsValve</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <exec.mainClass>org.ajames.tomcathttpsvalve.TomcatHttpsValve</exec.mainClass>
    </properties>
    
    <dependencies>
        <dependency>
            <groupId>org.apache.tomcat</groupId>
            <artifactId>tomcat-catalina</artifactId>
            <version>9.0.65</version>
        </dependency>
    </dependencies>
</project>

您可能需要针对您的Java版本调整编译器设置。
1.我创建了以下阀门类:

package org.ajames.tomcathttpsvalve;

import java.io.IOException;
import javax.servlet.ServletException;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import org.apache.catalina.valves.ValveBase;

// In server.xml:
// <Valve className="org.ajames.tomcathttpsvalve.TomcatHttpsValve"
//        fromPort="8080" toPort="8443" />
//
// This class is packaged as a JAR & placed in Tomcat's /lib
public class TomcatHttpsValve extends ValveBase {

    private final String fromScheme = "http";
    private final String toScheme = "https";
    private final int httpsDefaultPort = 443;
    private int fromPort; // see valve config for value
    private int toPort; // see valve config for value

    public TomcatHttpsValve() {
        super(true); // async supported
    }

    @Override
    public void invoke(Request req, Response resp) throws IOException, ServletException {
        if (req.getScheme().toLowerCase().equals(toScheme)) {
            // already using https:
            getNext().invoke(req, resp);
        } else {
            // need to redirect to https:
            resp.sendRedirect(buildNewReqUrl(req));
        }
    }

    private String buildNewReqUrl(Request req) {
        String scheme = req.getScheme();
        int port = req.getServerPort();

        if (scheme.toLowerCase().equals(fromScheme)) {
            scheme = toScheme;
        }

        if (port == fromPort) {
            port = toPort;
        }

        // build the new URL
        // assumes no userinfo (...//john.doe@...)
        StringBuilder sb = new StringBuilder();
        sb.append(scheme).append("://").append(req.getServerName());
        if (port != httpsDefaultPort) { // 443 is implicit with https
            sb.append(":").append(port);
        }
        sb.append(req.getRequestURI()); // (e.g. /foo/bar)
        if (req.getQueryString() != null) {
            sb.append("?").append(req.getQueryString());
        }

        return sb.toString();
    }

    public int getFromPort() {
        return fromPort;
    }

    public void setFromPort(String fromPort) {
        this.fromPort = Integer.parseInt(fromPort);
    }

    public int getToPort() {
        return toPort;
    }

    public void setToPort(String toPort) {
        this.toPort = Integer.parseInt(toPort);
    }
}

这会拦截请求URL并(如果需要)重定向到修改后的URL。
我将包含该类的JAR文件放在Tomcat lib主目录中。
1.我创建了一个新的阀元素:

<Valve className="org.ajames.tomcathttpsvalve.TomcatHttpsValve"
       fromPort="8080" toPort="8443" />

在我的例子中,我选择将这个值添加到Tomcat的server.xml文件的<host>部分,这意味着这个值适用于所有进入该主机的请求(在我的例子中,是localhost)。
如果您希望影响所有流量,也可以将其放置在<engine>部分中。
(You如果您希望对特定的Web应用程序进行更细粒度的控制,也可以将其放置在特定的<context>部分中。但这需要您自定义Jenkins安装,类似于方法一。)
使用Tomcat valve将您与使用Tomcat作为Jenkins应用程序的容器联系在一起。但是您不需要对Jenkins进行任何更改。
当然,在升级Tomcat时,您需要记住重新应用这些定制。如果升级到Tomcat 10+,您还需要使用jakarta包而不是javax包(使用相关版本的tomcat-catalina依赖项)重新构建valve。

相关问题