Skip to content
Permalink
Browse files

[JENKINS-44894] - Add options to disable random Cookie generation or …

…to specify a custom one (workaround for JENKINS-25046) (#9)

[JENKINS-44894] - Add options to disable random Cookie generation or to specify a custom one (workaround for JENKINS-25046)
  • Loading branch information...
oleg-nenashev committed Jun 14, 2017
1 parent f4f09b1 commit 7afa0adbd7a6b0f1391e7ebd3213e4a79ae45e3f
Showing with 73 additions and 17 deletions.
  1. +27 −0 README.md
  2. +46 −17 src/main/java/Main.java
@@ -3,4 +3,31 @@ This module defines the 'main' method for a self-contained web application that
embedded [Winstone](http://github.com/jenkinsci/winstone) and runs a web application without
needing a servlet container.


See Jenkins war module for how this module gets used by a .war file.

## Usage

This section describes particular use-cases of the executable WAR.

### Jetty Session IDs

The Executable WAR library has a custom handling of Jetty Session IDs by default.
In particular, by default it uses custom cookie names in order to prevent session collisions
when running multiple Jenkins instances on the same host.
Every startup the wrapper picks a new random cookie name (format: `JSESSIONID.${* random hex symbols}`).
The default lifetime of these cookies is 1 day, hence in some cases you may get into issues like [JENKINS-25046 (too many active cookies)](https://issues.jenkins-ci.org/browse/JENKINS-25046) when you restart Jenkins too often or use multiple instances.

Starting from version `TODO`, it is possible to customize the behavior via System Properties:

* `executableWar.jetty.disableCustomSeesionIdCookieName` -
(`boolean`, default: `false`) -
Disables usage of the custom cookie names when starting the WAR file.
If the flag is specified, the session ID will be defined by the internal Jetty logic.
In such case it becomes configurable via [Jetty configuration](http://www.eclipse.org/jetty/documentation/9.4.x/quick-start-configure.html) (XML config file, etc.).
* `executableWar.jetty.sessionIdCookieName` -
(`string`, default: `null`) -
Sets a custom Session ID Cookie name when `disableCustomSeesionIdCookieName` is `false`.
In such case the Jenkins administrator is responsible for preventing cookie collisions between Jenkins instances.


@@ -66,6 +66,26 @@

private static final Logger LOGGER = Logger.getLogger(Main.class.getName());

/**
* Sets custom session cookie name.
* It may be used to prevent randomization of JSESSIONID cookies and issues like
* <a href="https://issues.jenkins-ci.org/browse/JENKINS-25046">JENKINS-25046</a>.
* @since TODO
*/
private static final String JSESSIONID_COOKIE_NAME =
System.getProperty("executableWar.jetty.sessionIdCookieName");

/**
* Disables usage of the custom cookie names when starting the WAR file.
* If the flag is specified, the session ID will be defined by the internal Jetty logic.
* In such case it becomes configurable via
* <a href="http://www.eclipse.org/jetty/documentation/9.4.x/jetty-xml-config.html">Jetty XML Config file</a>>
* or via system properties.
* @since TODO
*/
private static final boolean DISABLE_CUSTOM_JSESSIONID_COOKIE_NAME =
Boolean.getBoolean("executableWar.jetty.disableCustomSeesionIdCookieName");

/**
* Reads <tt>WEB-INF/classes/dependencies.txt and builds "groupId:artifactId" -> "version" map.
*/
@@ -238,26 +258,35 @@ private static void _main(String[] args) throws Exception {
" --logfile = redirect log messages to this file\n" +
"{OPTIONS}");

/*
Set an unique cookie name.

if (!DISABLE_CUSTOM_JSESSIONID_COOKIE_NAME) {
/*
Set an unique cookie name.
As can be seen in discussions like http://stackoverflow.com/questions/1146112/jsessionid-collision-between-two-servers-on-same-ip-but-different-ports
and http://stackoverflow.com/questions/1612177/are-http-cookies-port-specific, RFC 2965 says
cookies from one port of one host may be sent to a different port of the same host.
This means if someone runs multiple Jenkins on different ports of the same host,
their sessions get mixed up.
As can be seen in discussions like http://stackoverflow.com/questions/1146112/jsessionid-collision-between-two-servers-on-same-ip-but-different-ports
and http://stackoverflow.com/questions/1612177/are-http-cookies-port-specific, RFC 2965 says
cookies from one port of one host may be sent to a different port of the same host.
This means if someone runs multiple Jenkins on different ports of the same host,
their sessions get mixed up.
To fix the problem, use unique session cookie name.
To fix the problem, use unique session cookie name.
This change breaks the cluster mode of Winstone, as all nodes in the cluster must share the same session cookie name.
Jenkins doesn't support clustered operation anyway, so we need to do this here, and not in Winstone.
*/
try {
Field f = cl.loadClass("winstone.WinstoneSession").getField("SESSION_COOKIE_NAME");
f.setAccessible(true);
f.set(null,"JSESSIONID."+UUID.randomUUID().toString().replace("-","").substring(0,8));
} catch (ClassNotFoundException e) {
// early versions of Winstone 2.x didn't have this
This change breaks the cluster mode of Winstone, as all nodes in the cluster must share the same session cookie name.
Jenkins doesn't support clustered operation anyway, so we need to do this here, and not in Winstone.
*/
try {
Field f = cl.loadClass("winstone.WinstoneSession").getField("SESSION_COOKIE_NAME");
f.setAccessible(true);
if (JSESSIONID_COOKIE_NAME != null) {
// Use the user-defined cookie name
f.set(null, JSESSIONID_COOKIE_NAME);
} else {
// Randomize session names by default to prevent collisions when running multiple Jenkins instances on the same host.
f.set(null,"JSESSIONID."+UUID.randomUUID().toString().replace("-","").substring(0,8));
}
} catch (ClassNotFoundException e) {
// early versions of Winstone 2.x didn't have this
}
}

// run

0 comments on commit 7afa0ad

Please sign in to comment.
You can’t perform that action at this time.