diff --git a/cli/src/main/java/hudson/cli/CLI.java b/cli/src/main/java/hudson/cli/CLI.java index 1b9b4856ad7e8f03d51a8b8662c2151ec13f7143..9c33baa358414584f74f40817aa10c1615519bef 100644 --- a/cli/src/main/java/hudson/cli/CLI.java +++ b/cli/src/main/java/hudson/cli/CLI.java @@ -23,6 +23,7 @@ */ package hudson.cli; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import hudson.cli.client.Messages; import java.io.DataInputStream; import javax.net.ssl.HostnameVerifier; @@ -175,6 +176,7 @@ public class CLI { HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory()); // bypass host name check, too. HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() { + @SuppressFBWarnings(value = "WEAK_HOSTNAME_VERIFIER", justification = "User set parameter to skip verifier.") public boolean verify(String s, SSLSession sslSession) { return true; } @@ -188,7 +190,7 @@ public class CLI { continue; } if(head.equals("-i") && args.size()>=2) { - File f = new File(args.get(1)); + File f = getFileFromArguments(args); if (!f.exists()) { printUsage(Messages.CLI_NoSuchFileExists(f)); return -1; @@ -290,7 +292,7 @@ public class CLI { if (userInfo != null) { factory = factory.basicAuth(userInfo); } else if (auth != null) { - factory = factory.basicAuth(auth.startsWith("@") ? FileUtils.readFileToString(new File(auth.substring(1)), Charset.defaultCharset()).trim() : auth); + factory = factory.basicAuth(auth.startsWith("@") ? readAuthFromFile(auth).trim() : auth); } if (mode == Mode.HTTP) { @@ -304,6 +306,16 @@ public class CLI { throw new AssertionError(); } + @SuppressFBWarnings(value = {"PATH_TRAVERSAL_IN", "URLCONNECTION_SSRF_FD"}, justification = "User provided values for running the program.") + private static String readAuthFromFile(String auth) throws IOException { + return FileUtils.readFileToString(new File(auth.substring(1)), Charset.defaultCharset()); + } + + @SuppressFBWarnings(value = {"PATH_TRAVERSAL_IN", "URLCONNECTION_SSRF_FD"}, justification = "User provided values for running the program.") + private static File getFileFromArguments(List args) { + return new File(args.get(1)); + } + private static int webSocketConnection(String url, List args, CLIConnectionFactory factory) throws Exception { LOGGER.fine(() -> "Trying to connect to " + url + " via plain protocol over WebSocket"); class CLIEndpoint extends Endpoint { diff --git a/cli/src/main/java/hudson/cli/FullDuplexHttpStream.java b/cli/src/main/java/hudson/cli/FullDuplexHttpStream.java index 723e97f16c26805a3550a0d9b8fcb17476396fee..fe8db4511691c96e00c4187fa5f6df936a5da32d 100644 --- a/cli/src/main/java/hudson/cli/FullDuplexHttpStream.java +++ b/cli/src/main/java/hudson/cli/FullDuplexHttpStream.java @@ -1,5 +1,7 @@ package hudson.cli; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; + import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -60,7 +62,7 @@ public class FullDuplexHttpStream { // server->client LOGGER.fine("establishing download side"); - HttpURLConnection con = (HttpURLConnection) target.openConnection(); + HttpURLConnection con = openHttpConnection(target); con.setDoOutput(true); // request POST to avoid caching con.setRequestMethod("POST"); con.addRequestProperty("Session", uuid.toString()); @@ -78,7 +80,7 @@ public class FullDuplexHttpStream { // client->server uses chunked encoded POST for unlimited capacity. LOGGER.fine("establishing upload side"); - con = (HttpURLConnection) target.openConnection(); + con = openHttpConnection(target); con.setDoOutput(true); // request POST con.setRequestMethod("POST"); con.setChunkedStreamingMode(0); @@ -92,10 +94,15 @@ public class FullDuplexHttpStream { LOGGER.fine("established upload side"); } - // As this transport mode is using POST, it is necessary to resolve possible redirections using GET first. + @SuppressFBWarnings(value = "URLCONNECTION_SSRF_FD", justification = "Client-side code doesn't involve SSRF.") + private HttpURLConnection openHttpConnection(URL target) throws IOException { + return (HttpURLConnection) target.openConnection(); + } + + // As this transport mode is using POST, it is necessary to resolve possible redirections using GET first. @SuppressFBWarnings(value = "URLCONNECTION_SSRF_FD", justification = "Client-side code doesn't involve SSRF.") private URL tryToResolveRedirects(URL base, String authorization) { try { - HttpURLConnection con = (HttpURLConnection) base.openConnection(); + HttpURLConnection con = openHttpConnection(base); if (authorization != null) { con.addRequestProperty("Authorization", authorization); } diff --git a/cli/src/main/java/hudson/cli/NoCheckTrustManager.java b/cli/src/main/java/hudson/cli/NoCheckTrustManager.java index c69b3330c21073ad54f34b7d4e527b2181f9e28d..cceacf2b21cb4b84d1ab1da4c798df9f19ee88c0 100644 --- a/cli/src/main/java/hudson/cli/NoCheckTrustManager.java +++ b/cli/src/main/java/hudson/cli/NoCheckTrustManager.java @@ -1,5 +1,7 @@ package hudson.cli; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; + import javax.net.ssl.X509TrustManager; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; @@ -8,12 +10,15 @@ import java.security.cert.X509Certificate; * @author Kohsuke Kawaguchi */ public class NoCheckTrustManager implements X509TrustManager { + @SuppressFBWarnings(value = "WEAK_TRUST_MANAGER", justification = "User set parameter to skip verifier.") public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { } + @SuppressFBWarnings(value = "WEAK_TRUST_MANAGER", justification = "User set parameter to skip verifier.") public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { } + @SuppressFBWarnings(value = "WEAK_TRUST_MANAGER", justification = "User set parameter to skip verifier.") public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; } diff --git a/cli/src/main/java/hudson/cli/SSHCLI.java b/cli/src/main/java/hudson/cli/SSHCLI.java index 39dc9210a3e1615bac888932c689d97ad4dd1b4d..5321536c5c629c6ff6bcbfa81c52eb66ed496a6a 100644 --- a/cli/src/main/java/hudson/cli/SSHCLI.java +++ b/cli/src/main/java/hudson/cli/SSHCLI.java @@ -61,11 +61,10 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; */ class SSHCLI { - @SuppressFBWarnings(value = "RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE", justification = "Due to whatever reason FindBugs reports it fot try-with-resources") static int sshConnection(String jenkinsUrl, String user, List args, PrivateKeyProvider provider, final boolean strictHostKey) throws IOException { Logger.getLogger(SecurityUtils.class.getName()).setLevel(Level.WARNING); // suppress: BouncyCastle not registered, using the default JCE provider URL url = new URL(jenkinsUrl + "login"); - URLConnection conn = url.openConnection(); + URLConnection conn = openConnection(url); CLI.verifyJenkinsConnection(conn); String endpointDescription = conn.getHeaderField("X-SSH-Endpoint"); @@ -131,6 +130,11 @@ class SSHCLI { } } + @SuppressFBWarnings(value = "URLCONNECTION_SSRF_FD", justification = "Client-side code doesn't involve SSRF.") + private static URLConnection openConnection(URL url) throws IOException { + return url.openConnection(); + } + private SSHCLI() {} } diff --git a/core/src/main/java/hudson/ClassicPluginStrategy.java b/core/src/main/java/hudson/ClassicPluginStrategy.java index c5369614de87123480c526ddea82e5158c046b1d..e3af9fc07cc00603f0957aecada01aa03cad639d 100644 --- a/core/src/main/java/hudson/ClassicPluginStrategy.java +++ b/core/src/main/java/hudson/ClassicPluginStrategy.java @@ -431,6 +431,7 @@ public class ClassicPluginStrategy implements PluginStrategy { return null; } + @SuppressFBWarnings(value = "PATH_TRAVERSAL_IN", justification = "Administrator action installing a plugin, which could do far worse.") private static File resolve(File base, String relative) { File rel = new File(relative); if(rel.isAbsolute()) diff --git a/core/src/main/java/hudson/Proc.java b/core/src/main/java/hudson/Proc.java index 6acb1ceebaf5f6e9af1c3a858a732d4a5d614de6..f387d6abcc4843a5309820a3dc330bc330aae49b 100644 --- a/core/src/main/java/hudson/Proc.java +++ b/core/src/main/java/hudson/Proc.java @@ -23,6 +23,7 @@ */ package hudson; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import hudson.Launcher.ProcStarter; import hudson.model.TaskListener; import hudson.remoting.Channel; @@ -215,6 +216,7 @@ public abstract class Proc { * @param err * null to redirect stderr to stdout. */ + @SuppressFBWarnings(value = "COMMAND_INJECTION", justification = "Command injection is the point of this old, barely used class.") public LocalProc(String[] cmd,String[] env,InputStream in,OutputStream out,OutputStream err,File workDir) throws IOException { this( calcName(cmd), stderr(environment(new ProcessBuilder(cmd),env).directory(workDir), err==null || err== SELFPUMP_OUTPUT), diff --git a/core/src/main/java/hudson/Util.java b/core/src/main/java/hudson/Util.java index 7775b4ca6afe4361266670c997ec4f7031f602f9..776fea2c416230a5d5237923d0e100fbc40876f8 100644 --- a/core/src/main/java/hudson/Util.java +++ b/core/src/main/java/hudson/Util.java @@ -589,6 +589,8 @@ public class Util { /** * Computes MD5 digest of the given input stream. * + * This method should only be used for non-security applications where the MD5 weakness is not a problem. + * * @param source * The stream will be closed by this method at the end of this method. * @return @@ -598,7 +600,7 @@ public class Util { @Nonnull public static String getDigestOf(@Nonnull InputStream source) throws IOException { try { - MessageDigest md5 = MessageDigest.getInstance("MD5"); + MessageDigest md5 = getMd5(); DigestInputStream in = new DigestInputStream(source, md5); // Note: IOUtils.copy() buffers the input internally, so there is no // need to use a BufferedInputStream. @@ -618,6 +620,14 @@ public class Util { */ } + // TODO JENKINS-60563 remove MD5 from all usages in Jenkins + @SuppressFBWarnings(value = "WEAK_MESSAGE_DIGEST_MD5", justification = + "This method should only be used for non-security applications where the MD5 weakness is not a problem.") + @Deprecated + private static MessageDigest getMd5() throws NoSuchAlgorithmException { + return MessageDigest.getInstance("MD5"); + } + @Nonnull public static String getDigestOf(@Nonnull String text) { try { diff --git a/core/src/main/java/hudson/cli/Connection.java b/core/src/main/java/hudson/cli/Connection.java index 1961447778d04ab829c9b550305ac016309bcd35..bdeb192fd3ee8fb2bd587354b23e4f0b4eb610f3 100644 --- a/core/src/main/java/hudson/cli/Connection.java +++ b/core/src/main/java/hudson/cli/Connection.java @@ -23,6 +23,7 @@ */ package hudson.cli; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import hudson.remoting.ClassFilter; import hudson.remoting.ObjectInputStreamEx; import hudson.remoting.SocketChannelStream; @@ -113,6 +114,8 @@ public class Connection { /** * Receives an object sent by {@link #writeObject(Object)} */ + // TODO JENKINS-60562 remove this class + @SuppressFBWarnings(value = "OBJECT_DESERIALIZATION", justification = "Not used. We should just remove it. Class is deprecated.") public T readObject() throws IOException, ClassNotFoundException { ObjectInputStream ois = new ObjectInputStreamEx(in, getClass().getClassLoader(), ClassFilter.DEFAULT); @@ -194,16 +197,20 @@ public class Connection { */ public Connection encryptConnection(SecretKey sessionKey, String algorithm) throws IOException, GeneralSecurityException { Cipher cout = Cipher.getInstance(algorithm); - cout.init(Cipher.ENCRYPT_MODE, sessionKey, new IvParameterSpec(sessionKey.getEncoded())); + cout.init(Cipher.ENCRYPT_MODE, sessionKey, createIv(sessionKey)); CipherOutputStream o = new CipherOutputStream(out, cout); Cipher cin = Cipher.getInstance(algorithm); - cin.init(Cipher.DECRYPT_MODE, sessionKey, new IvParameterSpec(sessionKey.getEncoded())); + cin.init(Cipher.DECRYPT_MODE, sessionKey, createIv(sessionKey)); CipherInputStream i = new CipherInputStream(in, cin); return new Connection(i,o); } + private IvParameterSpec createIv(SecretKey sessionKey) { + return new IvParameterSpec(sessionKey.getEncoded()); + } + /** * Given a byte array that contains arbitrary number of bytes, digests or expands those bits into the specified * number of bytes without loss of entropy. diff --git a/core/src/main/java/hudson/console/AnnotatedLargeText.java b/core/src/main/java/hudson/console/AnnotatedLargeText.java index c862d0c61b187ad53aa545b152064ed035e0fc56..36d2664e9208ba72d8cf890fb9986e2e2a3efe4b 100644 --- a/core/src/main/java/hudson/console/AnnotatedLargeText.java +++ b/core/src/main/java/hudson/console/AnnotatedLargeText.java @@ -25,6 +25,7 @@ */ package hudson.console; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import jenkins.model.Jenkins; import hudson.remoting.ObjectInputStreamEx; import java.util.concurrent.TimeUnit; @@ -128,7 +129,7 @@ public class AnnotatedLargeText extends LargeText { long timestamp = ois.readLong(); if (TimeUnit.HOURS.toMillis(1) > abs(System.currentTimeMillis()-timestamp)) // don't deserialize something too old to prevent a replay attack - return (ConsoleAnnotator) ois.readObject(); + return getConsoleAnnotator(ois); } catch (RuntimeException ex) { throw new IOException("Could not decode input", ex); } @@ -140,6 +141,11 @@ public class AnnotatedLargeText extends LargeText { return ConsoleAnnotator.initial(context); } + @SuppressFBWarnings(value = "OBJECT_DESERIALIZATION", justification = "Deserialization is protected by logic.") + private ConsoleAnnotator getConsoleAnnotator(ObjectInputStream ois) throws IOException, ClassNotFoundException { + return (ConsoleAnnotator) ois.readObject(); + } + @CheckReturnValue @Override public long writeLogTo(long start, Writer w) throws IOException { diff --git a/core/src/main/java/hudson/console/ConsoleNote.java b/core/src/main/java/hudson/console/ConsoleNote.java index 4d2e2c2530cbba3d8d3e4ca7333f4acc522e53f4..e55f7c2629eb4f2aee213826c0f36fa512ea0695 100644 --- a/core/src/main/java/hudson/console/ConsoleNote.java +++ b/core/src/main/java/hudson/console/ConsoleNote.java @@ -23,6 +23,7 @@ */ package hudson.console; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import hudson.ExtensionPoint; import hudson.Functions; import hudson.MarkupText; @@ -275,7 +276,7 @@ public abstract class ConsoleNote implements Serializable, Describable implements Serializable, Describable" + - "" + - "" + - "" + - "%n" + - "%n%n"+ - "Authentication required%n"+ - " - + + + + Context where the page is loaded. + + + Title of the HTML page. Rendered in the page content inside a <h1>. + + + The method to call from within the HudsonPrivateSecurityRealm. + + + Determines if the tag will include the captcha. + + + The wrapper for the data provided by the user and the error message(s) if any. Is null on first form display. + + +

${title}

-
+
-
+
${data.errorMessage}
-
+
${error.value}
- + @@ -55,17 +73,17 @@ THE SOFTWARE. - - - - + + + + diff --git a/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/_entryFormPage.jelly b/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/_entryFormPage.jelly index 8009ad6518ed8c94505bbb7bdc8f7e23aef4172b..cb30e27bdf831f9cb443c2862a071a44632b793d 100644 --- a/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/_entryFormPage.jelly +++ b/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/_entryFormPage.jelly @@ -22,28 +22,36 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --> - + - + + + + Corresponds to the "it" of Jelly, meaning the context where the page is loaded. + + + Title of the HTML page. + Rendered into <title> tag, in the page content inside a <h1> and as the label of the submit button. + + + The method to call from within the HudsonPrivateSecurityRealm. + + + Determines if the tag will include the captcha. + + + The wrapper for the data provided by the user and the error message(s) if any. Is null on first form display. + + - - - + -
- + + -
diff --git a/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/_entryFormPage/resources.css b/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/_entryFormPage/resources.css new file mode 100644 index 0000000000000000000000000000000000000000..18e07446425e6a75cdf769f7860ca3a15578a12a --- /dev/null +++ b/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/_entryFormPage/resources.css @@ -0,0 +1,12 @@ +input { + /* match width with captcha image */ + width:200px; +} + +.form-content { + margin: 2em; +} + +.form-content .error { + margin-bottom: 1em; +} diff --git a/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/addUser.jelly b/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/addUser.jelly index daacc17bfc479390f379266536a1f3bbc3f79344..b9b3f246c73901c866e70696b5a62157d26d2d31 100644 --- a/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/addUser.jelly +++ b/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/addUser.jelly @@ -26,6 +26,6 @@ THE SOFTWARE. Page for admin to create a new user --> - - - \ No newline at end of file + + + diff --git a/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/config.jelly b/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/config.jelly index 97571521688d05e3fd98b7b38db9b84ed3557d26..a36f9c14f0af1b0188019a67c53bcaf5cb040c0f 100644 --- a/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/config.jelly +++ b/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/config.jelly @@ -23,8 +23,7 @@ THE SOFTWARE. --> - + diff --git a/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/firstUser.jelly b/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/firstUser.jelly index 6ebd369ae0a1f0d7c10eaf619b13c221343d716d..b3568d1a6e1b86a3a57ad5ac7fc179291800a1be 100644 --- a/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/firstUser.jelly +++ b/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/firstUser.jelly @@ -26,6 +26,6 @@ THE SOFTWARE. This is used to create the first user. --> - - - \ No newline at end of file + + + diff --git a/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/index.jelly b/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/index.jelly index a7cad84726f1fda839af513793310c15b4aff4e3..29d3ffc4a2d7141f417e3f7d839dd728d2f405b6 100644 --- a/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/index.jelly +++ b/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/index.jelly @@ -23,7 +23,7 @@ THE SOFTWARE. --> - + @@ -32,20 +32,20 @@ THE SOFTWARE.
${%Username}:
${%Password}:
${%E-mail address}:
${%E-mail address}:
${%Enter text as shown}:
- [${%captcha}] + [${%captcha}]
- - - + diff --git a/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/loginLink.jelly b/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/loginLink.jelly index c2ef8305fa4827837d80e7c70a3665304b228549..ba75e740a89e557d9669617b78442c0af70b82b6 100644 --- a/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/loginLink.jelly +++ b/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/loginLink.jelly @@ -23,10 +23,10 @@ THE SOFTWARE. --> - + | ${%sign up} - \ No newline at end of file + diff --git a/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/sidepanel.jelly b/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/sidepanel.jelly index 6cc9f4456925a6c37cf58ff93097e8c7e479d847..8e3c84edcc1d74f4a66b41d6cd7b92316dc8486f 100644 --- a/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/sidepanel.jelly +++ b/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/sidepanel.jelly @@ -23,13 +23,13 @@ THE SOFTWARE. --> - + - - - + + + - \ No newline at end of file + diff --git a/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/signupWithFederatedIdentity.jelly b/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/signupWithFederatedIdentity.jelly index 8daec8d38125220336aadd180767915648741af5..83f9eef9eccf084c0b7563a85eb976a8c9511d83 100644 --- a/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/signupWithFederatedIdentity.jelly +++ b/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/signupWithFederatedIdentity.jelly @@ -26,6 +26,6 @@ THE SOFTWARE. User self sign up page. --> - - - \ No newline at end of file + + + diff --git a/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/success.jelly b/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/success.jelly index 59363c6d1cbd8ab070605305b08c8fbe96fe4253..a6f137e1a2aad75ae6b8a05da33d1ba048d37558 100644 --- a/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/success.jelly +++ b/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/success.jelly @@ -23,7 +23,7 @@ THE SOFTWARE. --> - + diff --git a/core/src/main/resources/hudson/security/SecurityRealm/signup.jelly b/core/src/main/resources/hudson/security/SecurityRealm/signup.jelly index 9f054b876cfefab2dba382142585351494f3f8e8..3609d384055b227c3b3f794348a6adb2dc5d4dd8 100644 --- a/core/src/main/resources/hudson/security/SecurityRealm/signup.jelly +++ b/core/src/main/resources/hudson/security/SecurityRealm/signup.jelly @@ -22,7 +22,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --> - + diff --git a/core/src/main/resources/lib/layout/hasPermission.jelly b/core/src/main/resources/lib/layout/hasPermission.jelly index d42a5f96891822fca9e2a7440d0c4f87bc853ab8..6371acc38293bee570cb849b13e2fd710701b74c 100644 --- a/core/src/main/resources/lib/layout/hasPermission.jelly +++ b/core/src/main/resources/lib/layout/hasPermission.jelly @@ -26,7 +26,13 @@ THE SOFTWARE. Renders the body only if the current user has the specified permission - + + By default it will reuse the current context. + If the provided value does not inherit from hudson.security.AccessControlled, + the tag will look for the first ancestor satisfying the condition. + The hasPermission will be performed against that value. + + permission object to check. If this is null, the body will be also rendered. @@ -34,4 +40,4 @@ THE SOFTWARE. - \ No newline at end of file + diff --git a/core/src/test/java/jenkins/util/xstream/XStreamDOMTest.java b/core/src/test/java/jenkins/util/xstream/XStreamDOMTest.java index 3acf389a4249844334ffd5952128625c0f327ffb..a53dff38e295eb827184ef689f06818d4ff5a645 100644 --- a/core/src/test/java/jenkins/util/xstream/XStreamDOMTest.java +++ b/core/src/test/java/jenkins/util/xstream/XStreamDOMTest.java @@ -27,8 +27,11 @@ import hudson.util.XStream2; import org.apache.commons.io.IOUtils; import org.junit.Before; import org.junit.Test; +import org.xmlunit.diff.DefaultNodeMatcher; +import org.xmlunit.diff.ElementSelectors; import static org.junit.Assert.*; +import static org.xmlunit.matchers.CompareMatcher.isSimilarTo; import java.io.IOException; import java.io.InputStream; @@ -62,7 +65,8 @@ public class XStreamDOMTest { Foo foo = createSomeFoo(); String xml = xs.toXML(foo); System.out.println(xml); - assertEquals(getTestData1().trim(), xml.trim()); + assertThat(getTestData1().trim(), isSimilarTo(xml.trim()).ignoreWhitespace() + .withNodeMatcher(new DefaultNodeMatcher(ElementSelectors.byNameAndText))); } private String getTestData1() throws IOException { @@ -100,7 +104,8 @@ public class XStreamDOMTest { String xml = xs.toXML(foo); System.out.println(xml); - assertEquals(getTestData1().trim(), xml.trim()); + assertThat(getTestData1().trim(), isSimilarTo(xml.trim()).ignoreWhitespace() + .withNodeMatcher(new DefaultNodeMatcher(ElementSelectors.byNameAndText))); } @Test diff --git a/pom.xml b/pom.xml index ef8a27e010c9ce45d1e0ef91664d17e208a89762..4467f8b81f6239adde94d681d1376b4dd99e8979 100755 --- a/pom.xml +++ b/pom.xml @@ -407,6 +407,20 @@ THE SOFTWARE. org.codehaus.mojo animal-sniffer-maven-plugin + + com.github.spotbugs + spotbugs-maven-plugin + + + + com.h3xstream.findsecbugs + findsecbugs-plugin + 1.10.1 + + + 768 + + diff --git a/src/findbugs/findbugs-excludes.xml b/src/findbugs/findbugs-excludes.xml index 665871ffd14825e3722ccbb547db0e05171a6fe8..b7e091076a3205eeb8b3fcecc33b53aed34d11ac 100644 --- a/src/findbugs/findbugs-excludes.xml +++ b/src/findbugs/findbugs-excludes.xml @@ -13,4 +13,12 @@ + + + + + + + + diff --git a/test/src/test/java/hudson/PluginManagerTest.java b/test/src/test/java/hudson/PluginManagerTest.java index 57cd87d9f9753336c40b4eed7389c7b17013ff2f..bb9ce486b828ab27f85a6253ea1ab9060675533d 100644 --- a/test/src/test/java/hudson/PluginManagerTest.java +++ b/test/src/test/java/hudson/PluginManagerTest.java @@ -503,6 +503,18 @@ public class PluginManagerTest { } } + @Issue("JENKINS-61071") + @Test + public void requireSystemInInitializer() throws Exception { + r.jenkins.setSecurityRealm(r.createDummySecurityRealm()); + r.jenkins.setAuthorizationStrategy(new MockAuthorizationStrategy()); + String pluginShortName = "require-system-in-initializer"; + dynamicLoad(pluginShortName + ".jpi"); + try (ACLContext context = ACL.as(User.getById("underprivileged", true).impersonate())) { + r.jenkins.pluginManager.start(Collections.singletonList(r.jenkins.pluginManager.getPlugin(pluginShortName))); + } + } + private void dynamicLoad(String plugin) throws IOException, InterruptedException, RestartRequiredException { PluginManagerUtil.dynamicLoad(plugin, r.jenkins); } diff --git a/test/src/test/resources/plugins/require-system-in-initializer.jpi b/test/src/test/resources/plugins/require-system-in-initializer.jpi new file mode 100644 index 0000000000000000000000000000000000000000..8c0aaf186cdf684b5279721818a996758e19ea76 Binary files /dev/null and b/test/src/test/resources/plugins/require-system-in-initializer.jpi differ diff --git a/war/pom.xml b/war/pom.xml index fa9d4986a7ba70f0a335582b8ec89d575f6565b4..1d33e2299e884221e8831c4310912f9bd718e8cc 100644 --- a/war/pom.xml +++ b/war/pom.xml @@ -360,7 +360,7 @@ THE SOFTWARE. org.jenkins-ci.plugins script-security - 1.68 + 1.70 hpi diff --git a/war/src/main/webapp/css/style.css b/war/src/main/webapp/css/style.css index b57dfd5dc412c99a0f63ef37315e32a246270ecd..252c86423b144e28c5c0d17c02212624eea2517a 100644 --- a/war/src/main/webapp/css/style.css +++ b/war/src/main/webapp/css/style.css @@ -522,6 +522,10 @@ table.bigtable.pane > tbody > tr > td:last-child { white-space: nowrap; } +.bigtable th.minimum-width { + width: 1px; +} + .bigtable td { vertical-align: middle; padding: 3px 4px 3px 4px;
+ ${%User ID} ${%Name} +
${user.id} ${user} - + - +