Issue
I have jenkins.war deployed on tomcat 9(on Linux) and configured it for http and https.
Configuration on 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>
Configuration on 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>
I'm able to redirect http to https with above configuration for tomcat when jenkins wasn't hosted. But after deploying jenkins.war redirecting http to https is not working.
Are there any other configuration changes required for redirecting http to https for jenkins?
Solution
Based on the notes in the answer from Mark Thomas, I tried two different approaches, both of which worked for me.
Both approaches also require the changes you already described in your question.
Approach One
Editing the security constraint in the Jenkins WAR.
For this I let Tomcat explode the WAR in the webapps
directory, and then edited the file at webapps/jenkins/WEB-INF/web.xml
. I commented out the following section:
<!-- 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> -->
Approach Two
I created a Tomcat valve, which I created as a JAR file, and then placed in Tomcat's main lib
directory.
I added a valve element to Tomcat, to activate the valve.
The specific steps:
I used the most recent version of Jenkins LTS (long term support) - version 2.346.3. Because this version of Jenkins does not support
jakarta
packages, I installed it on Tomcat 9 (forjavax
packages).I created a standard Java library project, one which is packaged into a JAR (not a WAR). The Maven POM:
<?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>
You may need to adjust the compiler settings for your version of Java.
- I created the following valve class:
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);
}
}
This intercepts the request URL and (if needed) redirects to a modified URL.
I placed the JAR file containing this class in the main Tomcat lib
directory.
- I created a new valve element:
<Valve className="org.ajames.tomcathttpsvalve.TomcatHttpsValve"
fromPort="8080" toPort="8443" />
In my case, I chose to add this to the <host>
section of my Tomcat's server.xml
file. This means that the valve applies to all requests coming in to that host (in my case, localhost
).
You can also place this inside the <engine>
section if you want to affect all traffic.
(You could also place this inside a specific <context>
section, if you want more granular control - for a specific web application. But this would require you to customize the Jenkins installation, similar to Approach One.)
Using a Tomcat valve ties you to using Tomcat as the container for your Jenkins application. But you do not need to make any changes to Jenkins.
You do, of course, need to remember to re-apply these customizations when upgrading Tomcat. And if upgrading to Tomcat 10+, you would also need to re-build the valve using jakarta
packages instead of javax
packages (with the relevant version of the tomcat-catalina
dependency).
Answered By - andrewJames
Answer Checked By - Clifford M. (JavaFixing Volunteer)