diff --git a/changelog.html b/changelog.html
index 728fcf8d4cdb9258128210abdf565a0017ef89b9..fc7a6c2f513cde99c139433436b2fab54a70706c 100644
--- a/changelog.html
+++ b/changelog.html
@@ -55,6 +55,11 @@ Upcoming changes
+
-
Prevent File descriptor leaks when reading plugin manifests.
@@ -82,7 +87,6 @@ Upcoming changes
from
INFO
to FINE
.
(PR #2510)
-
-
diff --git a/cli/pom.xml b/cli/pom.xml
index 3695688a20fde22d329888d0ee5118425ffd5351..540a52bee528b506f79e7a109b2fab97dd09c236 100644
--- a/cli/pom.xml
+++ b/cli/pom.xml
@@ -5,7 +5,7 @@
org.jenkins-ci.main
pom
- 2.19.3-SNAPSHOT
+ 2.19.5-SNAPSHOT
cli
diff --git a/core/pom.xml b/core/pom.xml
index 2682c8b485c8522cf677a777faba561b4e0bde9f..d469bcadabffeb33b20ce6f0d8d5612988a72c03 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -29,7 +29,7 @@ THE SOFTWARE.
org.jenkins-ci.main
pom
- 2.19.3-SNAPSHOT
+ 2.19.5-SNAPSHOT
jenkins-core
diff --git a/core/src/main/java/hudson/cli/CLIAction.java b/core/src/main/java/hudson/cli/CLIAction.java
index 66eef745b86b2ffe6ad0247a6de5a78b82f4fc4f..0053c278bc3ab5333f81f55470c3f9592244e774 100644
--- a/core/src/main/java/hudson/cli/CLIAction.java
+++ b/core/src/main/java/hudson/cli/CLIAction.java
@@ -63,12 +63,11 @@ public class CLIAction implements UnprotectedRootAction, StaplerProxy {
}
public String getDisplayName() {
-
return "Jenkins CLI";
}
public String getUrlName() {
- return "cli";
+ return jenkins.CLI.DISABLED ? null : "cli";
}
public void doCommand(StaplerRequest req, StaplerResponse rsp) throws ServletException, IOException {
diff --git a/core/src/main/java/hudson/cli/CliProtocol.java b/core/src/main/java/hudson/cli/CliProtocol.java
index f2160fe31f6121ad399007d35330863def725781..d663957fe9debe8998bb698ece5067fa40b410bd 100644
--- a/core/src/main/java/hudson/cli/CliProtocol.java
+++ b/core/src/main/java/hudson/cli/CliProtocol.java
@@ -42,7 +42,7 @@ public class CliProtocol extends AgentProtocol {
@Override
public String getName() {
- return "CLI-connect";
+ return jenkins.CLI.DISABLED ? null : "CLI-connect";
}
/**
diff --git a/core/src/main/java/hudson/cli/CliProtocol2.java b/core/src/main/java/hudson/cli/CliProtocol2.java
index cd7d8b04f64a9e51d7ce4f19bbc052c5a494d444..bb14599dbfea037d7d07517d828ffb9aa7f968b9 100644
--- a/core/src/main/java/hudson/cli/CliProtocol2.java
+++ b/core/src/main/java/hudson/cli/CliProtocol2.java
@@ -25,7 +25,7 @@ import java.security.Signature;
public class CliProtocol2 extends CliProtocol {
@Override
public String getName() {
- return "CLI2-connect";
+ return jenkins.CLI.DISABLED ? null : "CLI2-connect";
}
/**
diff --git a/core/src/main/java/jenkins/CLI.java b/core/src/main/java/jenkins/CLI.java
new file mode 100644
index 0000000000000000000000000000000000000000..970e59dc62db197646b2080c8aa91d0531ccd2af
--- /dev/null
+++ b/core/src/main/java/jenkins/CLI.java
@@ -0,0 +1,17 @@
+package jenkins;
+
+import org.kohsuke.accmod.Restricted;
+import org.kohsuke.accmod.restrictions.NoExternalUse;
+
+/**
+ * Kill switch to disable the entire Jenkins CLI system.
+ *
+ * Marked as no external use because the CLI subsystem is nearing EOL.
+ *
+ * @author Kohsuke Kawaguchi
+ */
+@Restricted(NoExternalUse.class)
+public class CLI {
+ // non-final to allow setting from $JENKINS_HOME/init.groovy.d
+ public static boolean DISABLED = Boolean.getBoolean(CLI.class.getName()+".disabled");
+}
diff --git a/core/src/main/java/jenkins/model/CauseOfInterruption.java b/core/src/main/java/jenkins/model/CauseOfInterruption.java
index 81dd16111d882ee4b997dd7ac8e07a61cd81ffcd..557110f2398865765b2014495b44db038490cc00 100644
--- a/core/src/main/java/jenkins/model/CauseOfInterruption.java
+++ b/core/src/main/java/jenkins/model/CauseOfInterruption.java
@@ -33,6 +33,7 @@ import org.kohsuke.stapler.export.ExportedBean;
import java.io.Serializable;
import java.util.Collections;
import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
/**
* Records why an {@linkplain Executor#interrupt() executor is interrupted}.
@@ -74,18 +75,46 @@ public abstract class CauseOfInterruption implements Serializable {
* Indicates that the build was interrupted from UI.
*/
public static final class UserInterruption extends CauseOfInterruption {
+
+ @Nonnull
private final String user;
- public UserInterruption(User user) {
+ public UserInterruption(@Nonnull User user) {
this.user = user.getId();
}
- public UserInterruption(String userId) {
+ public UserInterruption(@Nonnull String userId) {
this.user = userId;
}
- @CheckForNull
+ /**
+ * Gets ID of the user, who interrupted the build.
+ * @return User ID
+ * @since TODO
+ */
+ @Nonnull
+ public String getUserId() {
+ return user;
+ }
+
+ /**
+ * Gets user, who caused the interruption.
+ * @return User instance if it can be located.
+ * Result of {@link User#getUnknown()} otherwise
+ */
+ @Nonnull
public User getUser() {
+ final User userInstance = getUserOrNull();
+ return userInstance != null ? userInstance : User.getUnknown();
+ }
+
+ /**
+ * Gets user, who caused the interruption.
+ * @return User or {@code null} if it has not been found
+ * @since TODO
+ */
+ @CheckForNull
+ public User getUserOrNull() {
return User.get(user, false, Collections.emptyMap());
}
diff --git a/core/src/main/resources/jenkins/model/CauseOfInterruption/UserInterruption/summary.groovy b/core/src/main/resources/jenkins/model/CauseOfInterruption/UserInterruption/summary.groovy
index ec48cb9efaf362b6b4e0defe98c1f9c8e889172d..b75b2386f95bfcb7aaf612ec9f2a95f333255b65 100644
--- a/core/src/main/resources/jenkins/model/CauseOfInterruption/UserInterruption/summary.groovy
+++ b/core/src/main/resources/jenkins/model/CauseOfInterruption/UserInterruption/summary.groovy
@@ -1,4 +1,9 @@
package jenkins.model.CauseOfInterruption.UserInterruption;
// by default we just print the short description.
-raw(_("blurb",my.user.fullName, rootURL+'/'+my.user.url))
\ No newline at end of file
+def user = my.userOrNull
+if (user != null) {
+ raw(_("blurb", user.fullName, rootURL+'/'+user.url))
+} else {
+ raw(_("userNotFound", my.userId))
+}
diff --git a/core/src/main/resources/jenkins/model/CauseOfInterruption/UserInterruption/summary.properties b/core/src/main/resources/jenkins/model/CauseOfInterruption/UserInterruption/summary.properties
index 1f1f63c2bced9e8dcbda322ad0c3d6127ab5f4c4..1ada7d261b140d9a47bbaa4da7cdffd44a4b9b8e 100644
--- a/core/src/main/resources/jenkins/model/CauseOfInterruption/UserInterruption/summary.properties
+++ b/core/src/main/resources/jenkins/model/CauseOfInterruption/UserInterruption/summary.properties
@@ -1 +1,2 @@
-blurb=Aborted by user {0}
\ No newline at end of file
+blurb=Aborted by user {0}
+userNotFound=Aborted by user {0}
diff --git a/core/src/main/resources/jenkins/model/CauseOfInterruption/UserInterruption/summary_ja.properties b/core/src/main/resources/jenkins/model/CauseOfInterruption/UserInterruption/summary_ja.properties
index e2d2051a6e1b5c013e972a401894689fff2e3a17..3cd254db98c9992dd0aa682f0c28c4106dd2b9da 100644
--- a/core/src/main/resources/jenkins/model/CauseOfInterruption/UserInterruption/summary_ja.properties
+++ b/core/src/main/resources/jenkins/model/CauseOfInterruption/UserInterruption/summary_ja.properties
@@ -1 +1,2 @@
-blurb=\u30e6\u30fc\u30b6\u30fc {0} \u306b\u3088\u308a\u4e2d\u65ad
\ No newline at end of file
+blurb=\u30e6\u30fc\u30b6\u30fc {0} \u306b\u3088\u308a\u4e2d\u65ad
+userNotFound=\u30e6\u30fc\u30b6\u30fc {0} \u306b\u3088\u308a\u4e2d\u65ad
diff --git a/core/src/main/resources/jenkins/model/CauseOfInterruption/UserInterruption/summary_pl.properties b/core/src/main/resources/jenkins/model/CauseOfInterruption/UserInterruption/summary_pl.properties
index 0095ece665717b8c3e01065e4517b9530baa7cbc..d2c91f76b00ac81566300ef4844379c61cf9dadd 100644
--- a/core/src/main/resources/jenkins/model/CauseOfInterruption/UserInterruption/summary_pl.properties
+++ b/core/src/main/resources/jenkins/model/CauseOfInterruption/UserInterruption/summary_pl.properties
@@ -1 +1,2 @@
-blurb=Przerwane przez u\u017Cytkownika {0}
\ No newline at end of file
+blurb=Przerwane przez u\u017cytkownika {0}
+userNotFound=Przerwane przez u\u017cytkownika {0}
diff --git a/core/src/main/resources/jenkins/model/CauseOfInterruption/UserInterruption/summary_sr.properties b/core/src/main/resources/jenkins/model/CauseOfInterruption/UserInterruption/summary_sr.properties
new file mode 100644
index 0000000000000000000000000000000000000000..a88ce0631cae526ce3dc5bf038f65a498bd59a6a
--- /dev/null
+++ b/core/src/main/resources/jenkins/model/CauseOfInterruption/UserInterruption/summary_sr.properties
@@ -0,0 +1,4 @@
+# This file is under the MIT License by authors
+
+blurb=\u041e\u0442\u043a\u0430\u0437\u0430\u043d\u043e \u043a\u043e\u0440\u0438\u0441\u043d\u0438\u043a\u043e\u043c {0}
+userNotFound=\u041e\u0442\u043a\u0430\u0437\u0430\u043d\u043e \u043a\u043e\u0440\u0438\u0441\u043d\u0438\u043a\u043e\u043c {0}
diff --git a/core/src/main/resources/jenkins/model/CauseOfInterruption/UserInterruption/summary_zh_TW.properties b/core/src/main/resources/jenkins/model/CauseOfInterruption/UserInterruption/summary_zh_TW.properties
index db917957563b21c1f8043f882355428694831555..3b2ac62c063258e245c2815a36ef9baac269d8b5 100644
--- a/core/src/main/resources/jenkins/model/CauseOfInterruption/UserInterruption/summary_zh_TW.properties
+++ b/core/src/main/resources/jenkins/model/CauseOfInterruption/UserInterruption/summary_zh_TW.properties
@@ -22,3 +22,4 @@
# THE SOFTWARE.
blurb=\u7531\u4f7f\u7528\u8005 {0} \u4e2d\u6b62
+userNotFound=\u7531\u4f7f\u7528\u8005 {0} \u4e2d\u6b62
diff --git a/pom.xml b/pom.xml
index 7c42bbddb3f2fcfa2aa28d2e9ff421ea6b84a739..983d72ec5df7df1aaa845a49336feb7613fae0c3 100644
--- a/pom.xml
+++ b/pom.xml
@@ -33,7 +33,7 @@ THE SOFTWARE.
org.jenkins-ci.main
pom
- 2.19.3-SNAPSHOT
+ 2.19.5-SNAPSHOT
pom
Jenkins main module
@@ -180,7 +180,7 @@ THE SOFTWARE.
org.jenkins-ci.main
remoting
- 2.62.2
+ 2.62.3
diff --git a/test/pom.xml b/test/pom.xml
index aac5bdd583cfd281841d6fd45b78cc3685215e23..4f0b97d41e44c0f6dd5b94886a863a0b2d43a545 100644
--- a/test/pom.xml
+++ b/test/pom.xml
@@ -28,7 +28,7 @@ THE SOFTWARE.
org.jenkins-ci.main
pom
- 2.19.3-SNAPSHOT
+ 2.19.5-SNAPSHOT
test
@@ -175,6 +175,11 @@ THE SOFTWARE.
mockito-core
test
+
+ org.reflections
+ reflections
+ 0.9.9
+
org.codehaus.geb
geb-implicit-assertions
diff --git a/test/src/test/java/jenkins/CLITest.java b/test/src/test/java/jenkins/CLITest.java
new file mode 100644
index 0000000000000000000000000000000000000000..054d4df5a113d0e00ee9dbcbc08287aee6318d39
--- /dev/null
+++ b/test/src/test/java/jenkins/CLITest.java
@@ -0,0 +1,65 @@
+package jenkins;
+
+import hudson.cli.FullDuplexHttpStream;
+import hudson.model.Computer;
+import hudson.model.Failure;
+import hudson.remoting.Channel;
+import org.junit.Rule;
+import org.junit.Test;
+import org.jvnet.hudson.test.JenkinsRule;
+
+import java.io.FileNotFoundException;
+import java.net.URL;
+
+import static org.junit.Assert.*;
+
+/**
+ * @author Kohsuke Kawaguchi
+ */
+public class CLITest {
+ @Rule
+ public JenkinsRule j = new JenkinsRule();
+
+ /**
+ * Checks if the kill switch works correctly
+ */
+ @Test
+ public void killSwitch() throws Exception {
+ // this should succeed, as a control case
+ makeHttpCall();
+ makeJnlpCall();
+
+ CLI.DISABLED = true;
+ try {
+ try {
+ makeHttpCall();
+ fail("Should have been rejected");
+ } catch (FileNotFoundException e) {
+ // attempt to make a call should fail
+ }
+ try {
+ makeJnlpCall();
+ fail("Should have been rejected");
+ } catch (Exception e) {
+ // attempt to make a call should fail
+ e.printStackTrace();
+
+ // the current expected failure mode is EOFException, though we don't really care how it fails
+ }
+ } finally {
+ CLI.DISABLED = false;
+ }
+ }
+
+ private void makeHttpCall() throws Exception {
+ FullDuplexHttpStream con = new FullDuplexHttpStream(new URL(j.getURL(), "cli"));
+ Channel ch = new Channel("test connection", Computer.threadPoolForRemoting, con.getInputStream(), con.getOutputStream());
+ ch.close();
+ }
+
+ private void makeJnlpCall() throws Exception {
+ int r = hudson.cli.CLI._main(new String[]{"-s",j.getURL().toString(), "version"});
+ if (r!=0)
+ throw new Failure("CLI failed");
+ }
+}
diff --git a/test/src/test/java/jenkins/security/Security218CliTest.java b/test/src/test/java/jenkins/security/Security218CliTest.java
index ae4cbeac4d9208431d07453270cea780d7bb79f7..87d8026221411b2d1f1f99949fa71d32bc36d10f 100644
--- a/test/src/test/java/jenkins/security/Security218CliTest.java
+++ b/test/src/test/java/jenkins/security/Security218CliTest.java
@@ -32,6 +32,7 @@ import java.io.File;
import java.io.PrintStream;
import jenkins.security.security218.Payload;
import org.jenkinsci.remoting.RoleChecker;
+import org.junit.Ignore;
import org.junit.Test;
import static org.junit.Assert.*;
import org.junit.Rule;
@@ -45,7 +46,14 @@ public class Security218CliTest {
@Rule
public JenkinsRule r = new JenkinsRule();
-
+
+ @PresetData(PresetData.DataSet.ANONYMOUS_READONLY)
+ @Test
+ @Issue("SECURITY-317")
+ public void probeCommonsBeanutils1() throws Exception {
+ probe(Payload.CommonsBeanutils1, PayloadCaller.EXIT_CODE_REJECTED);
+ }
+
@PresetData(PresetData.DataSet.ANONYMOUS_READONLY)
@Test
@Issue("SECURITY-218")
@@ -61,6 +69,41 @@ public class Security218CliTest {
// in newer commons-collections version => remoting implementation should filter this class anyway
probe(Payload.CommonsCollections2, PayloadCaller.EXIT_CODE_REJECTED);
}
+
+ @PresetData(PresetData.DataSet.ANONYMOUS_READONLY)
+ @Test
+ @Issue("SECURITY-317")
+ public void probeCommonsCollections3() throws Exception {
+ probe(Payload.CommonsCollections3, PayloadCaller.EXIT_CODE_REJECTED);
+ }
+
+ @PresetData(PresetData.DataSet.ANONYMOUS_READONLY)
+ @Test
+ @Issue("SECURITY-317")
+ public void probeCommonsCollections4() throws Exception {
+ probe(Payload.CommonsCollections4, PayloadCaller.EXIT_CODE_REJECTED);
+ }
+
+ @PresetData(PresetData.DataSet.ANONYMOUS_READONLY)
+ @Test
+ @Issue("SECURITY-317")
+ public void probeCommonsCollections5() throws Exception {
+ probe(Payload.CommonsCollections5, PayloadCaller.EXIT_CODE_REJECTED);
+ }
+
+ @PresetData(PresetData.DataSet.ANONYMOUS_READONLY)
+ @Test
+ @Issue("SECURITY-317")
+ public void probeCommonsCollections6() throws Exception {
+ probe(Payload.CommonsCollections6, PayloadCaller.EXIT_CODE_REJECTED);
+ }
+
+ @PresetData(PresetData.DataSet.ANONYMOUS_READONLY)
+ @Test
+ @Issue("SECURITY-317")
+ public void probeFileUpload1() throws Exception {
+ probe(Payload.FileUpload1, 3);
+ }
@PresetData(PresetData.DataSet.ANONYMOUS_READONLY)
@Test
@@ -68,6 +111,34 @@ public class Security218CliTest {
public void probeGroovy1() throws Exception {
probe(Payload.Groovy1, PayloadCaller.EXIT_CODE_REJECTED);
}
+
+ @PresetData(PresetData.DataSet.ANONYMOUS_READONLY)
+ @Test
+ @Issue("SECURITY-317")
+ public void probeJdk7u21() throws Exception {
+ probe(Payload.Jdk7u21, PayloadCaller.EXIT_CODE_REJECTED);
+ }
+
+ @PresetData(PresetData.DataSet.ANONYMOUS_READONLY)
+ @Test
+ @Issue("SECURITY-317")
+ public void probeJRMPClient() throws Exception {
+ probe(Payload.JRMPClient, PayloadCaller.EXIT_CODE_REJECTED);
+ }
+
+ @PresetData(PresetData.DataSet.ANONYMOUS_READONLY)
+ @Test
+ @Issue("SECURITY-317")
+ public void probeJRMPListener() throws Exception {
+ probe(Payload.JRMPListener, 3);
+ }
+
+ @PresetData(PresetData.DataSet.ANONYMOUS_READONLY)
+ @Test
+ @Issue("SECURITY-317")
+ public void probeJSON1() throws Exception {
+ probe(Payload.JSON1, PayloadCaller.EXIT_CODE_REJECTED);
+ }
//TODO: Fix the conversion layer (not urgent)
// There is an issue in the conversion layer after the migration to another XALAN namespace
@@ -76,9 +147,29 @@ public class Security218CliTest {
@Test
@Issue("SECURITY-218")
public void probeSpring1() throws Exception {
+ // Reason it is 1 is that it is testing a test that is not in our version of Spring
+ // Caused by: java.lang.ClassNotFoundException: org.springframework.beans.factory.support.AutowireUtils$ObjectFactoryDelegatingInvocationHandler
probe(Payload.Spring1, 1);
}
+
+ @PresetData(PresetData.DataSet.ANONYMOUS_READONLY)
+ @Test
+ @Issue("SECURITY-317")
+ public void probeSpring2() throws Exception {
+ // Reason it is 1 is that it is testing a test that is not in our version of Spring 4
+ // Caused by: java.lang.ClassNotFoundException: org.springframework.core.SerializableTypeWrapper$TypeProvider
+ probe(Payload.Spring2, 1);
+ }
+ @PresetData(PresetData.DataSet.ANONYMOUS_READONLY)
+ @Test
+ @Issue("SECURITY-360")
+ public void ldap() throws Exception {
+ // with a proper fix, this should fail with EXIT_CODE_REJECTED
+ // otherwise this will fail with -1 exit code
+ probe(Payload.Ldap, PayloadCaller.EXIT_CODE_REJECTED);
+ }
+
private void probe(Payload payload, int expectedResultCode) throws Exception {
File file = File.createTempFile("security-218", payload + "-payload");
File moved = new File(file.getAbsolutePath() + "-moved");
diff --git a/test/src/test/java/jenkins/security/security218/Payload.java b/test/src/test/java/jenkins/security/security218/Payload.java
index 43dc97a995f9cc9b49c51c2c7982ca1ffb082d39..a08186ba3d20cf1c3f0b580a167ac1eb6065b8ab 100644
--- a/test/src/test/java/jenkins/security/security218/Payload.java
+++ b/test/src/test/java/jenkins/security/security218/Payload.java
@@ -23,11 +23,7 @@
*/
package jenkins.security.security218;
-import jenkins.security.security218.ysoserial.payloads.CommonsCollections1;
-import jenkins.security.security218.ysoserial.payloads.CommonsCollections2;
-import jenkins.security.security218.ysoserial.payloads.Groovy1;
-import jenkins.security.security218.ysoserial.payloads.ObjectPayload;
-import jenkins.security.security218.ysoserial.payloads.Spring1;
+import jenkins.security.security218.ysoserial.payloads.*;
/**
@@ -35,11 +31,24 @@ import jenkins.security.security218.ysoserial.payloads.Spring1;
* @author Oleg Nenashev
*/
public enum Payload {
+ CommonsBeanutils1(CommonsBeanutils1.class),
CommonsCollections1(CommonsCollections1.class),
CommonsCollections2(CommonsCollections2.class),
+ CommonsCollections3(CommonsCollections3.class),
+ CommonsCollections4(CommonsCollections4.class),
+ CommonsCollections5(CommonsCollections5.class),
+ CommonsCollections6(CommonsCollections6.class),
+ FileUpload1(FileUpload1.class),
Groovy1(Groovy1.class),
- Spring1(Spring1.class);
-
+ Jdk7u21(Jdk7u21.class),
+ JRMPClient(JRMPClient.class),
+ JRMPListener(JRMPListener.class),
+ JSON1(JSON1.class),
+ Spring1(Spring1.class),
+ Spring2(Spring2.class),
+ Ldap(Ldap.class),
+ ;
+
private final Class extends ObjectPayload> payloadClass;
private Payload(Class extends ObjectPayload> payloadClass) {
diff --git a/test/src/test/java/jenkins/security/security218/ysoserial/Deserializer.java b/test/src/test/java/jenkins/security/security218/ysoserial/Deserializer.java
new file mode 100755
index 0000000000000000000000000000000000000000..a74c904d79a75910062bfdb6d26c5e6fc4ed3f86
--- /dev/null
+++ b/test/src/test/java/jenkins/security/security218/ysoserial/Deserializer.java
@@ -0,0 +1,58 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2013 Chris Frohoff
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package jenkins.security.security218.ysoserial;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.util.concurrent.Callable;
+
+public class Deserializer implements Callable