Skip to content

Commit

Permalink
Merge branch 'master' into add-groups-to-command-palette
Browse files Browse the repository at this point in the history
  • Loading branch information
janfaracik authored Feb 11, 2025
2 parents 7c9e172 + 848ac9b commit 0ab3665
Show file tree
Hide file tree
Showing 59 changed files with 524 additions and 410 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
[![Gitter](https://img.shields.io/gitter/room/jenkinsci/jenkins)](https://app.gitter.im/#/room/#jenkinsci_jenkins:gitter.im)

In a nutshell, Jenkins is the leading open-source automation server.
Built with Java, it provides over 1,800 [plugins](https://plugins.jenkins.io/) to support automating virtually anything,
Built with Java, it provides over 2,000 [plugins](https://plugins.jenkins.io/) to support automating virtually anything,
so that humans can spend their time doing things machines cannot.

# What to Use Jenkins for and When to Use It
Expand Down
7 changes: 1 addition & 6 deletions bom/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -287,11 +287,6 @@ THE SOFTWARE.
<artifactId>localizer</artifactId>
<version>1.31</version>
</dependency>
<dependency>
<groupId>org.jvnet.robust-http-client</groupId>
<artifactId>robust-http-client</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>org.jvnet.winp</groupId>
<artifactId>winp</artifactId>
Expand Down Expand Up @@ -342,7 +337,7 @@ THE SOFTWARE.
<!-- provided by jcl-over-slf4j -->
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.3.4</version>
<version>1.3.5</version>
<scope>provided</scope>
</dependency>
</dependencies>
Expand Down
4 changes: 0 additions & 4 deletions core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -325,10 +325,6 @@ THE SOFTWARE.
<groupId>org.jvnet.localizer</groupId>
<artifactId>localizer</artifactId>
</dependency>
<dependency>
<groupId>org.jvnet.robust-http-client</groupId>
<artifactId>robust-http-client</artifactId>
</dependency>
<dependency>
<groupId>org.jvnet.winp</groupId>
<artifactId>winp</artifactId>
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/java/hudson/Functions.java
Original file line number Diff line number Diff line change
Expand Up @@ -1989,7 +1989,7 @@ public static String joinPath(String... components) {
*/
public static @CheckForNull String getConsoleUrl(WithConsoleUrl withConsoleUrl) {
String consoleUrl = withConsoleUrl.getConsoleUrl();
return consoleUrl != null ? Stapler.getCurrentRequest().getContextPath() + '/' + consoleUrl : null;
return consoleUrl != null ? Stapler.getCurrentRequest2().getContextPath() + '/' + consoleUrl : null;
}

/**
Expand Down
5 changes: 2 additions & 3 deletions core/src/main/java/hudson/ProxyConfiguration.java
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@
import jenkins.util.JenkinsJVM;
import jenkins.util.SystemProperties;
import org.jenkinsci.Symbol;
import org.jvnet.robust_http_client.RetryableHttpStream;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.NoExternalUse;
import org.kohsuke.stapler.DataBoundConstructor;
Expand Down Expand Up @@ -346,10 +345,10 @@ public static URLConnection open(URL url) throws IOException {
public static InputStream getInputStream(URL url) throws IOException {
final ProxyConfiguration p = get();
if (p == null)
return new RetryableHttpStream(url);
return ((HttpURLConnection) url.openConnection()).getInputStream();

Proxy proxy = p.createProxy(url.getHost());
InputStream is = new RetryableHttpStream(url, proxy);
InputStream is = ((HttpURLConnection) url.openConnection(proxy)).getInputStream();
if (p.getUserName() != null) {
// Add an authenticator which provides the credentials for proxy authentication
Authenticator.setDefault(p.authenticator);
Expand Down
29 changes: 13 additions & 16 deletions core/src/main/java/hudson/Util.java
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@
import java.util.Collections;
import java.util.Date;
import java.util.EnumSet;
import java.util.HexFormat;
import java.util.List;
import java.util.Locale;
import java.util.Map;
Expand All @@ -115,7 +116,6 @@
import jenkins.util.MemoryReductionUtil;
import jenkins.util.SystemProperties;
import jenkins.util.io.PathRemover;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.time.FastDateFormat;
import org.apache.tools.ant.BuildException;
Expand Down Expand Up @@ -635,7 +635,6 @@ public static String ensureEndsWith(@CheckForNull String subject, @CheckForNull
* The stream will be closed by this method at the end of this method.
* @return
* 32-char wide string
* @see DigestUtils#md5Hex(InputStream)
*/
@NonNull
public static String getDigestOf(@NonNull InputStream source) throws IOException {
Expand Down Expand Up @@ -710,13 +709,7 @@ public static SecretKey toAes128Key(@NonNull String s) {

@NonNull
public static String toHexString(@NonNull byte[] data, int start, int len) {
StringBuilder buf = new StringBuilder();
for (int i = 0; i < len; i++) {
int b = data[start + i] & 0xFF;
if (b < 16) buf.append('0');
buf.append(Integer.toHexString(b));
}
return buf.toString();
return HexFormat.of().formatHex(data, start, len);
}

@NonNull
Expand All @@ -726,12 +719,7 @@ public static String toHexString(@NonNull byte[] bytes) {

@NonNull
public static byte[] fromHexString(@NonNull String data) {
if (data.length() % 2 != 0)
throw new IllegalArgumentException("data must have an even number of hexadecimal digits");
byte[] r = new byte[data.length() / 2];
for (int i = 0; i < data.length(); i += 2)
r[i / 2] = (byte) Integer.parseInt(data.substring(i, i + 2), 16);
return r;
return HexFormat.of().parseHex(data);
}

/**
Expand Down Expand Up @@ -1992,9 +1980,18 @@ public static byte[] getSHA256DigestOf(@NonNull byte[] input) {
* Returns Hex string of SHA-256 Digest of passed input
*/
@Restricted(NoExternalUse.class)
public static String getHexOfSHA256DigestOf(byte[] input) throws IOException {
public static String getHexOfSHA256DigestOf(byte[] input) {
//get hex string of sha 256 of payload
byte[] payloadDigest = Util.getSHA256DigestOf(input);
return (payloadDigest != null) ? Util.toHexString(payloadDigest) : null;
}


/**
* Returns Hex string of SHA-256 Digest of passed string
*/
@Restricted(NoExternalUse.class)
public static String getHexOfSHA256DigestOf(String input) {
return getHexOfSHA256DigestOf(input.getBytes(StandardCharsets.UTF_8));
}
}
7 changes: 7 additions & 0 deletions core/src/main/java/hudson/scheduler/CronTab.java
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,11 @@ public Calendar ceil(long t) {
* (e.g. Jun 31) date, or at least a date too rare to be useful. This addresses JENKINS-41864 and was added in 2.49
*/
public Calendar ceil(Calendar cal) {
if (cal.get(Calendar.SECOND) > 0 || cal.get(Calendar.MILLISECOND) > 0) {
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
cal.add(Calendar.MINUTE, 1);
}
Calendar twoYearsFuture = (Calendar) cal.clone();
twoYearsFuture.add(Calendar.YEAR, 2);
OUTER:
Expand Down Expand Up @@ -440,6 +445,8 @@ public Calendar floor(long t) {
* (e.g. Jun 31) date, or at least a date too rare to be useful. This addresses JENKINS-41864 and was added in 2.49
*/
public Calendar floor(Calendar cal) {
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
Calendar twoYearsAgo = (Calendar) cal.clone();
twoYearsAgo.add(Calendar.YEAR, -2);

Expand Down
2 changes: 1 addition & 1 deletion core/src/main/java/jenkins/console/ConsoleUrlProvider.java
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ default Descriptor<ConsoleUrlProvider> getDescriptor() {
* @return the URL for the console for the specified build, relative to the web server root
*/
static @NonNull String getRedirectUrl(Run<?, ?> run) {
return Stapler.getCurrentRequest().getContextPath() + '/' + run.getConsoleUrl();
return Stapler.getCurrentRequest2().getContextPath() + '/' + run.getConsoleUrl();
}

static List<ConsoleUrlProvider> all() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import net.sf.json.JSONException;
import net.sf.json.JSONObject;
import org.jenkinsci.Symbol;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerRequest2;

/**
* Configures check interval for computer retention.
Expand Down Expand Up @@ -56,7 +56,7 @@ private void setComputerRetentionCheckInterval(int interval) throws IllegalArgum
}

@Override
public boolean configure(StaplerRequest req, JSONObject json) throws FormException {
public boolean configure(StaplerRequest2 req, JSONObject json) throws FormException {
try {
final int interval = json.getInt("computerRetentionCheckInterval");
setComputerRetentionCheckInterval(interval);
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/java/jenkins/model/GlobalConfiguration.java
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public String getGlobalConfigPage() {
@Override
public boolean configure(StaplerRequest2 req, JSONObject json) throws FormException {
if (Util.isOverridden(GlobalConfiguration.class, getClass(), "configure", StaplerRequest.class, JSONObject.class)) {
return configure(StaplerRequest.fromStaplerRequest2(req), json);
return configure(req != null ? StaplerRequest.fromStaplerRequest2(req) : null, json);
} else {
return configureImpl(req, json);
}
Expand Down
3 changes: 3 additions & 0 deletions core/src/main/java/jenkins/model/Jenkins.java
Original file line number Diff line number Diff line change
Expand Up @@ -974,6 +974,9 @@ protected Jenkins(File root, ServletContext context, PluginManager pluginManager
ClassFilterImpl.register();
LOGGER.info("Starting version " + getVersion());

// Sanity check that we can load the confidential store. Fail fast if we can't.
ConfidentialStore.get();

// initialization consists of ...
executeReactor(is,
pluginManager.initTasks(is), // loading and preparing plugins
Expand Down
37 changes: 31 additions & 6 deletions core/src/main/java/jenkins/security/DefaultConfidentialStore.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package jenkins.security;

import edu.umd.cs.findbugs.annotations.NonNull;
import hudson.FilePath;
import hudson.Util;
import hudson.util.Secret;
Expand All @@ -19,19 +20,35 @@
import javax.crypto.CipherOutputStream;
import javax.crypto.SecretKey;
import jenkins.model.Jenkins;
import jenkins.util.SystemProperties;

/**
* Default portable implementation of {@link ConfidentialStore} that uses
* a directory inside $JENKINS_HOME.
*
* The master key is also stored in this same directory.
* <p>
* The master key is stored by default in <code>$JENKINS_HOME/secrets/master.key</code> but another location can be provided using the system property <code>jenkins.master.key.file</code>.
* <p>
* It is also possible to prevent the generation of the master key file using the system property <code>-Djenkins.master.key.readOnly</code>. In this case, the master key file must be provided or startup will fail.
*
* @author Kohsuke Kawaguchi
*/
// @MetaInfServices --- not annotated because this is the fallback implementation
public class DefaultConfidentialStore extends ConfidentialStore {
static final String MASTER_KEY_FILE_SYSTEM_PROPERTY = DefaultConfidentialStore.class.getName() + ".file";
static final String MASTER_KEY_READONLY_SYSTEM_PROPERTY_NAME = DefaultConfidentialStore.class.getName() + ".readOnly";

private final SecureRandom sr = new SecureRandom();

@NonNull
private static File getMasterKeyFile(File rootDir) {
var jenkinsMasterKey = SystemProperties.getString(MASTER_KEY_FILE_SYSTEM_PROPERTY);
if (jenkinsMasterKey != null) {
return new File(jenkinsMasterKey);
} else {
return new File(rootDir, "master.key");
}
}

/**
* Directory that stores individual keys.
*/
Expand All @@ -51,18 +68,26 @@ public DefaultConfidentialStore() throws IOException, InterruptedException {
}

public DefaultConfidentialStore(File rootDir) throws IOException, InterruptedException {
this(rootDir, getMasterKeyFile(rootDir));
}

protected DefaultConfidentialStore(File rootDir, File keyFile) throws IOException, InterruptedException {
this.rootDir = rootDir;
if (rootDir.mkdirs()) {
// protect this directory. but don't change the permission of the existing directory
// in case the administrator changed this.
new FilePath(rootDir).chmod(0700);
}

TextFile masterSecret = new TextFile(new File(rootDir, "master.key"));
TextFile masterSecret = new TextFile(keyFile);
if (!masterSecret.exists()) {
// we are only going to use small number of bits (since export control limits AES key length)
// but let's generate a long enough key anyway
masterSecret.write(Util.toHexString(randomBytes(128)));
if (SystemProperties.getBoolean(MASTER_KEY_READONLY_SYSTEM_PROPERTY_NAME)) {
throw new IOException(masterSecret + " does not exist and system property " + MASTER_KEY_READONLY_SYSTEM_PROPERTY_NAME + " is set. You must provide a valid master key file.");
} else {
// we are only going to use small number of bits (since export control limits AES key length)
// but let's generate a long enough key anyway
masterSecret.write(Util.toHexString(randomBytes(128)));
}
}
this.masterKey = Util.toAes128Key(masterSecret.readTrim());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import hudson.BulkChange;
import hudson.Extension;
import hudson.Util;
import hudson.model.User;
import hudson.model.UserProperty;
import hudson.model.UserPropertyDescriptor;
Expand All @@ -39,7 +40,6 @@
import jenkins.model.Jenkins;
import jenkins.security.LastGrantedAuthoritiesProperty;
import jenkins.util.SystemProperties;
import org.apache.commons.codec.binary.Hex;
import org.jenkinsci.Symbol;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.DoNotUse;
Expand Down Expand Up @@ -103,7 +103,7 @@ private void renewSeedInternal() {
byte[] bytes = new byte[SEED_NUM_BYTES];
while (Objects.equals(newSeed, currentSeed)) {
RANDOM.nextBytes(bytes);
newSeed = new String(Hex.encodeHex(bytes));
newSeed = Util.toHexString(bytes);
}
this.seed = newSeed;
}
Expand Down
4 changes: 2 additions & 2 deletions core/src/main/java/jenkins/telemetry/Telemetry.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import hudson.ExtensionPoint;
import hudson.PluginWrapper;
import hudson.ProxyConfiguration;
import hudson.Util;
import hudson.model.AsyncPeriodicWork;
import hudson.model.TaskListener;
import hudson.model.UsageStatistics;
Expand All @@ -51,7 +52,6 @@
import jenkins.model.Jenkins;
import jenkins.util.SystemProperties;
import net.sf.json.JSONObject;
import org.apache.commons.codec.digest.DigestUtils;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.NoExternalUse;

Expand Down Expand Up @@ -221,7 +221,7 @@ protected void execute(TaskListener listener) throws IOException, InterruptedExc
wrappedData.put("type", telemetry.getId());
wrappedData.put("payload", data);
String correlationId = ExtensionList.lookupSingleton(Correlator.class).getCorrelationId();
wrappedData.put("correlator", DigestUtils.sha256Hex(correlationId + telemetry.getId()));
wrappedData.put("correlator", Util.getHexOfSHA256DigestOf(correlationId + telemetry.getId()));

String body = wrappedData.toString();
if (LOGGER.isLoggable(Level.FINEST)) {
Expand Down
9 changes: 4 additions & 5 deletions core/src/main/java/jenkins/util/JSONSignatureValidator.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package jenkins.util;

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import hudson.Util;
import hudson.util.FormValidation;
import java.io.ByteArrayInputStream;
import java.io.File;
Expand Down Expand Up @@ -33,8 +34,6 @@
import java.util.logging.Logger;
import jenkins.model.Jenkins;
import net.sf.json.JSONObject;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.io.output.TeeOutputStream;
import org.jvnet.hudson.crypto.CertificateUtil;
import org.jvnet.hudson.crypto.SignatureOutputStream;
Expand Down Expand Up @@ -221,10 +220,10 @@ private boolean verifySignature(Signature signature, String providedSignature) {
// This approach might look unnecessarily clever, but short of having redundant Signature instances,
// there doesn't seem to be a better approach for this.
try {
if (signature.verify(Hex.decodeHex(providedSignature.toCharArray()))) {
if (signature.verify(Util.fromHexString(providedSignature))) {
return true;
}
} catch (SignatureException | DecoderException ignore) {
} catch (SignatureException | IllegalArgumentException ignore) {
// ignore
}

Expand All @@ -242,7 +241,7 @@ private boolean verifySignature(Signature signature, String providedSignature) {
* Utility method supporting both possible digest formats: Base64 and Hex
*/
private boolean digestMatches(byte[] digest, String providedDigest) {
return providedDigest.equalsIgnoreCase(Hex.encodeHexString(digest)) || providedDigest.equalsIgnoreCase(Base64.getEncoder().encodeToString(digest));
return providedDigest.equalsIgnoreCase(Util.toHexString(digest)) || providedDigest.equalsIgnoreCase(Base64.getEncoder().encodeToString(digest));
}


Expand Down
Loading

0 comments on commit 0ab3665

Please sign in to comment.