diff --git a/core/src/main/java/hudson/util/SecretRewriter.java b/core/src/main/java/hudson/util/SecretRewriter.java deleted file mode 100644 index 4e50158523..0000000000 --- a/core/src/main/java/hudson/util/SecretRewriter.java +++ /dev/null @@ -1,213 +0,0 @@ -package hudson.util; - -import hudson.Functions; -import hudson.Util; -import hudson.model.TaskListener; -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.PrintWriter; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.InvalidPathException; -import java.security.GeneralSecurityException; -import java.security.InvalidKeyException; -import java.util.Base64; -import java.util.HashSet; -import java.util.Set; -import javax.crypto.Cipher; -import javax.crypto.SecretKey; - -/** - * Rewrites XML files by looking for Secrets that are stored with the old key and replaces them - * by the new encrypted values. - * - * @author Kohsuke Kawaguchi - */ -public class SecretRewriter { - private final Cipher cipher; - private final SecretKey key; - - /** - * How many files have been scanned? - */ - private int count; - - /** - * Canonical paths of the directories we are recursing to protect - * against symlink induced cycles. - */ - private Set callstack = new HashSet<>(); - - public SecretRewriter() throws GeneralSecurityException { - cipher = Secret.getCipher("AES"); - key = HistoricalSecrets.getLegacyKey(); - } - - /** @deprecated SECURITY-376: {@code backupDirectory} is ignored */ - @Deprecated - public SecretRewriter(File backupDirectory) throws GeneralSecurityException { - this(); - } - - private String tryRewrite(String s) throws InvalidKeyException { - if (s.length() < 24) - return s; // Encrypting "" in Secret produces 24-letter characters, so this must be the minimum length - if (!isBase64(s)) - return s; // decode throws IOException if the input is not base64, and this is also a very quick way to filter - - byte[] in; - try { - in = Base64.getDecoder().decode(s.getBytes(StandardCharsets.UTF_8)); - } catch (IllegalArgumentException e) { - return s; // not a valid base64 - } - cipher.init(Cipher.DECRYPT_MODE, key); - Secret sec = HistoricalSecrets.tryDecrypt(cipher, in); - if (sec != null) // matched - return sec.getEncryptedValue(); // replace by the new encrypted value - else // not encrypted with the legacy key. leave it unmodified - return s; - } - - /** @deprecated SECURITY-376: {@code backup} is ignored */ - @Deprecated - public boolean rewrite(File f, File backup) throws InvalidKeyException, IOException { - return rewrite(f); - } - - public boolean rewrite(File f) throws InvalidKeyException, IOException { - - AtomicFileWriter w = new AtomicFileWriter(f.toPath(), StandardCharsets.UTF_8); - try { - boolean modified = false; // did we actually change anything? - try (PrintWriter out = new PrintWriter(new BufferedWriter(w)); - InputStream fin = Files.newInputStream(Util.fileToPath(f)); - BufferedReader r = new BufferedReader(new InputStreamReader(fin, StandardCharsets.UTF_8))) { - String line; - StringBuilder buf = new StringBuilder(); - - while ((line = r.readLine()) != null) { - int copied = 0; - buf.setLength(0); - while (true) { - int sidx = line.indexOf('>', copied); - if (sidx < 0) break; - int eidx = line.indexOf('<', sidx); - if (eidx < 0) break; - - String elementText = line.substring(sidx + 1, eidx); - String replacement = tryRewrite(elementText); - if (!replacement.equals(elementText)) - modified = true; - - buf.append(line, copied, sidx + 1); - buf.append(replacement); - copied = eidx; - } - buf.append(line.substring(copied)); - out.println(buf); - } - } - - if (modified) { - w.commit(); - } - return modified; - } finally { - w.abort(); - } - } - - - /** - * Recursively scans and rewrites a directory. - * - * This method shouldn't abort just because one file fails to rewrite. - * - * @return - * Number of files that were actually rewritten. - */ - // synchronized to prevent accidental concurrent use. this instance is not thread safe - public synchronized int rewriteRecursive(File dir, TaskListener listener) throws InvalidKeyException { - return rewriteRecursive(dir, "", listener); - } - - private int rewriteRecursive(File dir, String relative, TaskListener listener) throws InvalidKeyException { - String canonical; - try { - canonical = dir.toPath().toRealPath().toString(); - } catch (IOException | InvalidPathException e) { - canonical = dir.getAbsolutePath(); // - } - if (!callstack.add(canonical)) { - listener.getLogger().println("Cycle detected: " + dir); - return 0; - } - - try { - File[] children = dir.listFiles(); - if (children == null) return 0; - - int rewritten = 0; - for (File child : children) { - String cn = child.getName(); - if (cn.endsWith(".xml")) { - if (count++ % 100 == 0) - listener.getLogger().println("Scanning " + child); - try { - if (rewrite(child)) { - listener.getLogger().println("Rewritten " + child); - rewritten++; - } - } catch (IOException e) { - Functions.printStackTrace(e, listener.error("Failed to rewrite " + child)); - } - } - if (child.isDirectory()) { - if (!isIgnoredDir(child)) - rewritten += rewriteRecursive(child, - relative.isEmpty() ? cn : relative + '/' + cn, - listener); - } - } - return rewritten; - } finally { - callstack.remove(canonical); - } - } - - /** - * Decides if this directory is worth visiting or not. - */ - protected boolean isIgnoredDir(File dir) { - // ignoring the workspace and the artifacts directories. Both of them - // are potentially large and they do not store any secrets. - String n = dir.getName(); - return n.equals("workspace") || n.equals("artifacts") - || n.equals("plugins") // no mutable data here - || n.equals(".") || n.equals(".."); - } - - private static boolean isBase64(char ch) { - return ch < 128 && IS_BASE64[ch]; - } - - private static boolean isBase64(String s) { - for (int i = 0; i < s.length(); i++) - if (!isBase64(s.charAt(i))) - return false; - return true; - } - - private static final boolean[] IS_BASE64 = new boolean[128]; - - static { - String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; - for (int i = 0; i < chars.length(); i++) - IS_BASE64[chars.charAt(i)] = true; - } -} diff --git a/core/src/main/java/jenkins/management/AsynchronousAdministrativeMonitor.java b/core/src/main/java/jenkins/management/AsynchronousAdministrativeMonitor.java index 7ebc732518..2884439681 100644 --- a/core/src/main/java/jenkins/management/AsynchronousAdministrativeMonitor.java +++ b/core/src/main/java/jenkins/management/AsynchronousAdministrativeMonitor.java @@ -17,7 +17,6 @@ import java.nio.charset.Charset; import java.util.logging.Level; import java.util.logging.Logger; import jenkins.model.Jenkins; -import jenkins.security.RekeySecretAdminMonitor; /** * Convenient partial implementation of {@link AdministrativeMonitor} that involves a background "fixing" action @@ -27,9 +26,6 @@ import jenkins.security.RekeySecretAdminMonitor; * A subclass defines what that background fixing actually does in {@link #fix(TaskListener)}. The logging output * from it gets persisted, and this class provides a "/log" view that allows the administrator to monitor its progress. * - *

- * See {@link RekeySecretAdminMonitor} for an example of how to subtype this class. - * * @author Kohsuke Kawaguchi */ public abstract class AsynchronousAdministrativeMonitor extends AdministrativeMonitor { diff --git a/core/src/main/java/jenkins/security/RekeySecretAdminMonitor.java b/core/src/main/java/jenkins/security/RekeySecretAdminMonitor.java deleted file mode 100644 index c3b5480045..0000000000 --- a/core/src/main/java/jenkins/security/RekeySecretAdminMonitor.java +++ /dev/null @@ -1,160 +0,0 @@ -package jenkins.security; - -import hudson.Extension; -import hudson.Functions; -import hudson.Util; -import hudson.init.InitMilestone; -import hudson.init.Initializer; -import hudson.model.TaskListener; -import hudson.util.HttpResponses; -import hudson.util.SecretRewriter; -import hudson.util.VersionNumber; -import java.io.File; -import java.io.IOException; -import java.io.PrintStream; -import java.security.GeneralSecurityException; -import java.util.Date; -import java.util.logging.Level; -import java.util.logging.Logger; -import jenkins.management.AsynchronousAdministrativeMonitor; -import jenkins.model.Jenkins; -import jenkins.util.io.FileBoolean; -import org.jenkinsci.Symbol; -import org.kohsuke.stapler.HttpResponse; -import org.kohsuke.stapler.StaplerRequest; -import org.kohsuke.stapler.interceptor.RequirePOST; - -/** - * Warns the administrator to run {@link SecretRewriter} - * - * @author Kohsuke Kawaguchi - */ -@Extension @Symbol("rekeySecret") -public class RekeySecretAdminMonitor extends AsynchronousAdministrativeMonitor { - - /** - * Whether we detected a need to run the rewrite program. - * Once we set it to true, we'll never turn it off. - * - * If the admin decides to dismiss this warning, we use {@link #isEnabled()} for that. - * - * In this way we can correctly differentiate all the different states. - */ - private final FileBoolean needed = state("needed"); - - /** - * If the scanning process has run to the completion, we set to this true. - */ - private final FileBoolean done = state("done"); - - /** - * If the rewrite process is scheduled upon the next boot. - */ - private final FileBoolean scanOnBoot = state("scanOnBoot"); - - @SuppressWarnings("OverridableMethodCallInConstructor") // should have been final - public RekeySecretAdminMonitor() throws IOException { - // if JENKINS_HOME existed <1.497, we need to offer rewrite - // this computation needs to be done and the value be captured, - // since $JENKINS_HOME/config.xml can be saved later before the user has - // actually rewritten XML files. - Jenkins j = Jenkins.get(); - if (j.isUpgradedFromBefore(new VersionNumber("1.496.*")) - && new FileBoolean(new File(j.getRootDir(), "secret.key.not-so-secret")).isOff()) - needed.on(); - Util.deleteRecursive(new File(getBaseDir(), "backups")); // SECURITY-376: no longer used - } - - @Override - public boolean isActivated() { - return needed.isOn(); - } - - /** - * Indicates that the re-keying has run to the completion. - */ - public boolean isDone() { - return done.isOn(); - } - - public void setNeeded() { - needed.on(); - } - - public boolean isScanOnBoot() { - return scanOnBoot.isOn(); - } - - @Override - public boolean isSecurity() { - return true; - } - - @RequirePOST - public HttpResponse doScan(StaplerRequest req) throws IOException, GeneralSecurityException { - if (req.hasParameter("background")) { - start(false); - } else - if (req.hasParameter("schedule")) { - scanOnBoot.on(); - } else - if (req.hasParameter("dismiss")) { - disable(true); - } else - throw HttpResponses.error(400, "Invalid request submission: " + req.getParameterMap()); - - return HttpResponses.redirectViaContextPath("/manage"); - } - - - private FileBoolean state(String name) { - return new FileBoolean(new File(getBaseDir(), name)); - } - - @Initializer(fatal = false, after = InitMilestone.PLUGINS_STARTED, before = InitMilestone.EXTENSIONS_AUGMENTED) - // as early as possible, but this needs to be late enough that the ConfidentialStore is available - public void scanOnReboot() throws InterruptedException, IOException, GeneralSecurityException { - FileBoolean flag = scanOnBoot; - if (flag.isOn()) { - flag.off(); - start(false).join(); - // block the boot until the rewrite process is complete - // don't let the failure in RekeyThread block Jenkins boot. - } - } - - @Override - public String getDisplayName() { - return Messages.RekeySecretAdminMonitor_DisplayName(); - } - - /** - * Rewrite log file. - */ - @Override - protected File getLogFile() { - return new File(getBaseDir(), "rekey.log"); - } - - @Override - protected void fix(TaskListener listener) throws Exception { - LOGGER.info("Initiating a re-keying of secrets. See " + getLogFile()); - - SecretRewriter rewriter = new SecretRewriter(); - - try { - PrintStream log = listener.getLogger(); - log.println("Started re-keying " + new Date()); - int count = rewriter.rewriteRecursive(Jenkins.get().getRootDir(), listener); - log.printf("Completed re-keying %d files on %s%n", count, new Date()); - new RekeySecretAdminMonitor().done.on(); - LOGGER.info("Secret re-keying completed"); - } catch (Exception e) { - LOGGER.log(Level.SEVERE, "Fatal failure in re-keying secrets", e); - Functions.printStackTrace(e, listener.error("Fatal failure in rewriting secrets")); - } - } - - private static final Logger LOGGER = Logger.getLogger(RekeySecretAdminMonitor.class.getName()); - -} diff --git a/core/src/main/resources/jenkins/security/Messages.properties b/core/src/main/resources/jenkins/security/Messages.properties index 7227f7e838..4fb04f7c96 100644 --- a/core/src/main/resources/jenkins/security/Messages.properties +++ b/core/src/main/resources/jenkins/security/Messages.properties @@ -27,7 +27,6 @@ ApiTokenProperty.ChangeToken.SuccessHidden=

Updated. You need to login as th ApiTokenProperty.ChangeToken.CapabilityNotAllowed=
Capability to generate a legacy token without an existing one is currently disabled in the security configuration
ApiTokenProperty.LegacyTokenName=Legacy Token ApiTokenProperty.NoLegacyToken=This user currently does not have a legacy token -RekeySecretAdminMonitor.DisplayName=Re-keying UpdateSiteWarningsMonitor.DisplayName=Update Site Warnings Token.Created.on=Token created on {0} diff --git a/core/src/main/resources/jenkins/security/Messages_bg.properties b/core/src/main/resources/jenkins/security/Messages_bg.properties index 97f31a1227..f5edaa4758 100644 --- a/core/src/main/resources/jenkins/security/Messages_bg.properties +++ b/core/src/main/resources/jenkins/security/Messages_bg.properties @@ -29,8 +29,6 @@ ApiTokenProperty.ChangeToken.Success=\ ApiTokenProperty.ChangeToken.SuccessHidden=\
Променен. Трябва да влезете като потребителя, за да видите низа за\ идентификация
-RekeySecretAdminMonitor.DisplayName=\ - Създаване на нов ключ # Update Site Warnings UpdateSiteWarningsMonitor.DisplayName=\ Предупреждения от сайтовете за обновления diff --git a/core/src/main/resources/jenkins/security/Messages_de.properties b/core/src/main/resources/jenkins/security/Messages_de.properties index 8c4c528750..a07807be9b 100644 --- a/core/src/main/resources/jenkins/security/Messages_de.properties +++ b/core/src/main/resources/jenkins/security/Messages_de.properties @@ -22,7 +22,6 @@ UpdateSiteWarningsMonitor.DisplayName=Warnungen des Update-Centers ApiTokenProperty.DisplayName=API-Token -RekeySecretAdminMonitor.DisplayName=Erneute Verschlüsselung ApiTokenProperty.ChangeToken.TokenIsHidden=Token wird nicht angezeigt ApiTokenProperty.ChangeToken.Success=
Aktualisiert. Der Token wird oben angezeigt.
ApiTokenProperty.ChangeToken.SuccessHidden=
Aktualisiert. Der Token wird nur dem Nutzer angezeigt.
diff --git a/core/src/main/resources/jenkins/security/Messages_it.properties b/core/src/main/resources/jenkins/security/Messages_it.properties index 5a6f6c985e..442f8dfc64 100644 --- a/core/src/main/resources/jenkins/security/Messages_it.properties +++ b/core/src/main/resources/jenkins/security/Messages_it.properties @@ -35,7 +35,6 @@ ApiTokenProperty.LegacyTokenName=Token legacy ApiTokenProperty.NoLegacyToken=Quest''utente non dispone attualmente di un \ token legacy. QueueItemAuthenticatorMonitor.DisplayName=Controllo accessi per le compilazioni -RekeySecretAdminMonitor.DisplayName=Modifica chiave ResourceDomainConfiguration.DisplayName=Raccomandazione dominio risorse ResourceDomainConfiguration.Empty=Senza un URL radice risorse, le risorse \ saranno servite dal dominio principale con l''intestazione \ diff --git a/core/src/main/resources/jenkins/security/Messages_ja.properties b/core/src/main/resources/jenkins/security/Messages_ja.properties index f958d55bf9..4043218d7f 100644 --- a/core/src/main/resources/jenkins/security/Messages_ja.properties +++ b/core/src/main/resources/jenkins/security/Messages_ja.properties @@ -22,5 +22,4 @@ ApiTokenProperty.DisplayName=APIトークン ApiTokenProperty.ChangeToken.Success=
更新しました
-RekeySecretAdminMonitor.DisplayName=キーの再生成 Token.Created.on={0}に作成されたトークン diff --git a/core/src/main/resources/jenkins/security/Messages_pt_BR.properties b/core/src/main/resources/jenkins/security/Messages_pt_BR.properties index beb5e0fc01..9921e25171 100644 --- a/core/src/main/resources/jenkins/security/Messages_pt_BR.properties +++ b/core/src/main/resources/jenkins/security/Messages_pt_BR.properties @@ -21,7 +21,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -RekeySecretAdminMonitor.DisplayName=Rechaveamento ApiTokenProperty.ChangeToken.Success=
Atualizado
ApiTokenProperty.DisplayName=Passe de API ResourceDomainConfiguration.NeedsRootURL=Só é possível configurar a URL raiz do recurso se a URL do Jenkins estiver \ diff --git a/core/src/main/resources/jenkins/security/Messages_ru.properties b/core/src/main/resources/jenkins/security/Messages_ru.properties index d69f827145..e580044a23 100644 --- a/core/src/main/resources/jenkins/security/Messages_ru.properties +++ b/core/src/main/resources/jenkins/security/Messages_ru.properties @@ -29,7 +29,6 @@ ApiTokenProperty.ChangeToken.CapabilityNotAllowed=
Возможность п уже существующего, отключена в настройках безопасности
ApiTokenProperty.LegacyTokenName=Токен предыдущей версии ApiTokenProperty.NoLegacyToken=У этого пользователя нет токена предыдущей версии -RekeySecretAdminMonitor.DisplayName=Смена ключей UpdateSiteWarningsMonitor.DisplayName=Предупреждения от сайтов обновлений Token.Created.on=Токен создан {0} diff --git a/core/src/main/resources/jenkins/security/Messages_sr.properties b/core/src/main/resources/jenkins/security/Messages_sr.properties index 0f698a1027..9c80fcbfdd 100644 --- a/core/src/main/resources/jenkins/security/Messages_sr.properties +++ b/core/src/main/resources/jenkins/security/Messages_sr.properties @@ -4,4 +4,3 @@ ApiTokenProperty.DisplayName=Токен за АПИ ApiTokenProperty.ChangeToken.TokenIsHidden=Токен је сакривен ApiTokenProperty.ChangeToken.Success=
Ажурирано. Проверите нови токен приказан изнад.
ApiTokenProperty.ChangeToken.SuccessHidden=
Ажурирано. Морате се пријавити као корисник да би могли проверити токен.
-RekeySecretAdminMonitor.DisplayName=Поново хеширање diff --git a/core/src/main/resources/jenkins/security/Messages_sv_SE.properties b/core/src/main/resources/jenkins/security/Messages_sv_SE.properties index 587e203dd5..c577663747 100644 --- a/core/src/main/resources/jenkins/security/Messages_sv_SE.properties +++ b/core/src/main/resources/jenkins/security/Messages_sv_SE.properties @@ -27,7 +27,6 @@ ApiTokenProperty.ChangeToken.SuccessHidden=
Uppdaterades. Du måste logga in ApiTokenProperty.ChangeToken.CapabilityNotAllowed=
Möjligheten att generera en äldre token utan en befintlig är för närvarande inaktiverad i säkerhetskonfigurationen
ApiTokenProperty.LegacyTokenName=Äldre token ApiTokenProperty.NoLegacyToken=Den här användaren har för närvarande ingen äldre token -RekeySecretAdminMonitor.DisplayName=Ange nyckel igen UpdateSiteWarningsMonitor.DisplayName=Uppdatera webbplatsvarningar Token.Created.on=Token skapades {0} diff --git a/core/src/main/resources/jenkins/security/Messages_zh_TW.properties b/core/src/main/resources/jenkins/security/Messages_zh_TW.properties index 4a65b17bc5..7ce2b9ccb4 100644 --- a/core/src/main/resources/jenkins/security/Messages_zh_TW.properties +++ b/core/src/main/resources/jenkins/security/Messages_zh_TW.properties @@ -22,4 +22,3 @@ ApiTokenProperty.DisplayName=API Token ApiTokenProperty.ChangeToken.Success=
已更新
-RekeySecretAdminMonitor.DisplayName=金鑰重套 diff --git a/core/src/main/resources/jenkins/security/RekeySecretAdminMonitor/description.jelly b/core/src/main/resources/jenkins/security/RekeySecretAdminMonitor/description.jelly deleted file mode 100644 index bb405e9319..0000000000 --- a/core/src/main/resources/jenkins/security/RekeySecretAdminMonitor/description.jelly +++ /dev/null @@ -1,4 +0,0 @@ - - - ${%blurb} - diff --git a/core/src/main/resources/jenkins/security/RekeySecretAdminMonitor/description.properties b/core/src/main/resources/jenkins/security/RekeySecretAdminMonitor/description.properties deleted file mode 100644 index e74250b62a..0000000000 --- a/core/src/main/resources/jenkins/security/RekeySecretAdminMonitor/description.properties +++ /dev/null @@ -1 +0,0 @@ -blurb = Informs about the need to perform secret re-keying due to a security vulnerability that was fixed in 2013. diff --git a/core/src/main/resources/jenkins/security/RekeySecretAdminMonitor/description_fr.properties b/core/src/main/resources/jenkins/security/RekeySecretAdminMonitor/description_fr.properties deleted file mode 100644 index d90c590de9..0000000000 --- a/core/src/main/resources/jenkins/security/RekeySecretAdminMonitor/description_fr.properties +++ /dev/null @@ -1 +0,0 @@ -blurb = Informe à propos de la nécessité de regénérer une clé de chiffrement à cause d''une vulnérabilité de sécurité corrigée en 2013. diff --git a/core/src/main/resources/jenkins/security/RekeySecretAdminMonitor/description_pt_BR.properties b/core/src/main/resources/jenkins/security/RekeySecretAdminMonitor/description_pt_BR.properties deleted file mode 100644 index 9ff0f6b076..0000000000 --- a/core/src/main/resources/jenkins/security/RekeySecretAdminMonitor/description_pt_BR.properties +++ /dev/null @@ -1,23 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-, Kohsuke Kawaguchi, Sun Microsystems, Inc., and a number of other of contributors -# -# 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. - -blurb=Informa sobre a necessidade de recriar o chaveamento de segredo devido a vulnerabilidade de segurança corrigida em 2013. diff --git a/core/src/main/resources/jenkins/security/RekeySecretAdminMonitor/description_ru.properties b/core/src/main/resources/jenkins/security/RekeySecretAdminMonitor/description_ru.properties deleted file mode 100644 index d53bc95fb4..0000000000 --- a/core/src/main/resources/jenkins/security/RekeySecretAdminMonitor/description_ru.properties +++ /dev/null @@ -1,2 +0,0 @@ -blurb = Информирует о надобности смены ключей секретов из-за уязвимости, исправленной в 2013. diff --git a/core/src/main/resources/jenkins/security/RekeySecretAdminMonitor/description_sv_SE.properties b/core/src/main/resources/jenkins/security/RekeySecretAdminMonitor/description_sv_SE.properties deleted file mode 100644 index 7864657a7e..0000000000 --- a/core/src/main/resources/jenkins/security/RekeySecretAdminMonitor/description_sv_SE.properties +++ /dev/null @@ -1,23 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-, Kohsuke Kawaguchi, Sun Microsystems, Inc., and a number of other of contributors -# -# 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. - -blurb=Informerar när en hemlig nyckel behöver anges igen på grund av en säkerhetsrisk som fixades 2013. diff --git a/core/src/main/resources/jenkins/security/RekeySecretAdminMonitor/message.groovy b/core/src/main/resources/jenkins/security/RekeySecretAdminMonitor/message.groovy deleted file mode 100644 index e481b70094..0000000000 --- a/core/src/main/resources/jenkins/security/RekeySecretAdminMonitor/message.groovy +++ /dev/null @@ -1,60 +0,0 @@ -/* -The MIT License - -Copyright (c) 2013, CloudBees, Inc. - -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.RekeySecretAdminMonitor - -def f = namespace(lib.FormTagLib) - -if (!my.isDone()) { - div(class:"jenkins-alert jenkins-alert-danger") { - raw _("pleaseRekeyAsap", app.rootDir, my.url) - } -} - -if (my.isFixingActive()) { - div(class:"jenkins-alert jenkins-alert-info") { - raw _("rekeyInProgress", my.url) - } -} else if (my.logFile.exists()) { - if (my.isDone()) { - div(class:"jenkins-alert jenkins-alert-info") { - raw _("rekeySuccessful", my.url) - } - } else { - div(class:"jenkins-alert jenkins-alert-warning") { - raw _("rekeyHadProblems", my.url) - } - } -} - -form(method: "post", action: "${rootURL}/${my.url}/scan", name:"rekey") { - f.submit(name: "background", value:_("Re-key in background now")) - if (my.isScanOnBoot()) { - button(type: "button", class: "jenkins-button jenkins-button--primary", disabled: "true") { - raw _("Re-keying currently scheduled during the next startup") - } - } else { - f.submit(name: "schedule", value:_("Schedule a re-key during the next startup")) - } - f.submit(name: "dismiss", value:_("Dismiss")) -} diff --git a/core/src/main/resources/jenkins/security/RekeySecretAdminMonitor/message.properties b/core/src/main/resources/jenkins/security/RekeySecretAdminMonitor/message.properties deleted file mode 100644 index d239da3b9e..0000000000 --- a/core/src/main/resources/jenkins/security/RekeySecretAdminMonitor/message.properties +++ /dev/null @@ -1,17 +0,0 @@ -pleaseRekeyAsap=\ - Because of a security vulnerability discovered earlier, we need to \ - change the encryption key used to protect secrets in your configuration files on the disk. \ - This process scans a large portion of your $JENKINS_HOME ({0}), \ - find encrypted data, re-key them, which will take some time. \ - See this document for more implications about different ways of doing this \ - (or not doing this.) This operation can be safely run in background, but cautious users \ - are recommended to take backups. - -rekeyInProgress=Re-keying is in progress. You can check the log. - -rekeySuccessful=\ - Secrets in your $JENKINS_HOME has been re-keyed successfully. \ - Please check the log, confirm the success, and then dismiss or re-run. - -rekeyHadProblems=\ - Re-keying has completed, but there were problems. Please check the log. diff --git a/core/src/main/resources/jenkins/security/RekeySecretAdminMonitor/message_fr.properties b/core/src/main/resources/jenkins/security/RekeySecretAdminMonitor/message_fr.properties deleted file mode 100644 index 155f9ce200..0000000000 --- a/core/src/main/resources/jenkins/security/RekeySecretAdminMonitor/message_fr.properties +++ /dev/null @@ -1,17 +0,0 @@ -pleaseRekeyAsap=\ - À cause de la vulnérabilité de sécurité découverte précédemment, nous devons \ - changer la clé de chiffrement utilisée pour protéger vos fichiers de configuration stockés sur disque. \ - Ce processus scanne une large portion de votre $JENKINS_HOME ({0}), \ - trouve les données chiffrées et les rechiffre, ce qui prendre du temps. \ - Consulter ce document pour plus d''informations sur les différentes façons de le faire \ - (ou pas). Cette opération peut s''exécuter de manière sûre en tâche de fond, mais nous recommandons aux utilisateurs précautionneux \ - d''effectuer des sauvegardes. - -rekeyInProgress=Rechiffrement en cours. Vous pouvez consulter les logs. - -rekeySuccessful=\ - Les secrets dans votre $JENKINS_HOME ont été rechiffrés avec succès. \ - Veuillez consulter les logs, confirmer le succès ou réexécuter le cas échéant. - -rekeyHadProblems=\ - Le rechiffrement est terminé, mais il y a eu des problèmes. Veuillez consulter les logs. diff --git a/core/src/main/resources/jenkins/security/RekeySecretAdminMonitor/message_it.properties b/core/src/main/resources/jenkins/security/RekeySecretAdminMonitor/message_it.properties deleted file mode 100644 index bdf1de25cd..0000000000 --- a/core/src/main/resources/jenkins/security/RekeySecretAdminMonitor/message_it.properties +++ /dev/null @@ -1,52 +0,0 @@ -# The MIT License -# -# Italian localization plugin for Jenkins -# Copyright © 2020 Alessandro Menti -# -# 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. - -Dismiss=Nascondi -pleaseRekeyAsap=A causa di una vulnerabilità di sicurezza scoperta in precedenza, \ - è necessario modificare la chiave crittografica utilizzata per proteggere i \ - segreti salvati nei file di configurazione su disco. Questa procedura \ - esegue la scansione della maggior parte della directory \ - $JENKINS_HOME ({0}), trova i dati crittografati e \ - li cripta nuovamente con la nuova chiave; tutte queste operazioni \ - richiedono del tempo. Si veda questo documento per le implicazioni derivanti dallo \ - scegliere una modalità anziché un''altra (o dal non eseguire \ - quest''operazione). Quest''operazione può essere eseguita in secondo piano \ - in modo sicuro, ma gli utenti più prudenti potrebbero voler eseguire delle \ - copie di backup. -Re-key\ in\ background\ now=Cripta ora tutti i dati con una nuova chiave in \ - secondo piano -Re-keying\ currently\ scheduled\ during\ the\ next\ startup=La modifica \ - della chiave è attualmente pianificata al prossimo avvio -rekeyHadProblems=La modifica della chiave è stata completata, ma si sono \ - verificati dei problemi. Controllare il log. -rekeyInProgress=La modifica della chiave è in corso. È \ - possibile controllare il log. -rekeySuccessful=I segreti salvati nella directory $JENKINS_HOME \ - sono stati criptati con successo con la nuova chiave. \ - Controllare il log, verificare che l''operazione sia stata eseguita \ - correttamente e quindi nascondere il messaggio oppure eseguire nuovamente \ - l''operazione. -Schedule\ a\ re-key\ during\ the\ next\ startup=Pianifica la modifica della \ - chiave al prossimo avvio diff --git a/core/src/main/resources/jenkins/security/RekeySecretAdminMonitor/message_pt_BR.properties b/core/src/main/resources/jenkins/security/RekeySecretAdminMonitor/message_pt_BR.properties deleted file mode 100644 index 0085368d2d..0000000000 --- a/core/src/main/resources/jenkins/security/RekeySecretAdminMonitor/message_pt_BR.properties +++ /dev/null @@ -1,38 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-, Kohsuke Kawaguchi, Sun Microsystems, Inc., and a number -# of other of contributors. -# Copyright (c) 2022- Jenkins contributors. -# 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. -pleaseRekeyAsap=Por conta da \ - falha de segurança \ - descoberta anteriormente precisamos mudar a chave de criptografia utilizada para proteger os segredos nos seus \ - arquivos de configuração disponíveis em disco. Este processo verifica uma larga porção do seu \ - $JENKINS_HOME ({0}), busca por dados criptografados e os criptografa novamente, o que irá \ - levar algum tempo. Veja \ - este documento para \ - maiores implicações sobre os modos diferentes de fazer (ou não) isto. Esta operação pode ser executada seguramente \ - em plano de fundo, mas usuários mais cautelosos considerem-se avisados para criar cópias de segurança. -rekeyInProgress=O processo de criptografar novamente está em progresso. Você pode verificar o \ - registro de execução. -rekeySuccessful=Segredos no seu $JENKINS_HOME foram recriptogrados novamente. \ - Por favor, verifique o registro de execução, confirme se tudo ocorreu com sucesso ou execute \ - novamente. -rekeyHadProblems=A recriptografia está concluída, mas ocorreram problemas. Por favor revise os registros \ - de execução. diff --git a/core/src/main/resources/jenkins/security/RekeySecretAdminMonitor/message_ru.properties b/core/src/main/resources/jenkins/security/RekeySecretAdminMonitor/message_ru.properties deleted file mode 100644 index cc48b8cb15..0000000000 --- a/core/src/main/resources/jenkins/security/RekeySecretAdminMonitor/message_ru.properties +++ /dev/null @@ -1,25 +0,0 @@ -pleaseRekeyAsap=\ - Из-за уязвимости, \ - обнаруженной ранее, необходимо \ - сменить ключ шифрования, используемый для защиты секретов в файлах конфигурации на диске. \ - Этот процесс просканирует большую часть директории $JENKINS_HOME ({0}), \ - найдёт шифрованные данные и сменит ключ. Это займёт некоторое время. \ - Больше информации о последствиях разных способов выполнения этой операции (или бездействия) \ - см. в этом документе. \ - Эту операцию безопасно выполнять в фоновом режиме, но осторожным пользователям \ - рекомендуется сделать резервную копию. - -rekeyInProgress=Выполняется смена ключа. Вы можете просмотреть лог. - -rekeySuccessful=\ - Ключ секретов в $JENKINS_HOME успешно сменён. \ - Пожалуйста, просмотрите лог, убедитесь, что операция успешна, затем скройте это уведомление \ - или перезапустите операцию. - -rekeyHadProblems=\ - Смена ключей завершена, но есть проблемы. Пожалуйста, просмотрите лог. - -Re-key\ in\ background\ now=Сменить ключи в фоновом режиме сейчас -Schedule\ a\ re-key\ during\ the\ next\ startup=Запланировать смену ключей при следующем запуске -Re-keying\ currently\ scheduled\ during\ the\ next\ startup=Смена ключей запланирована при следующем запуске -Dismiss=Скрыть diff --git a/core/src/main/resources/jenkins/security/RekeySecretAdminMonitor/message_sr.properties b/core/src/main/resources/jenkins/security/RekeySecretAdminMonitor/message_sr.properties deleted file mode 100644 index 0f3190504f..0000000000 --- a/core/src/main/resources/jenkins/security/RekeySecretAdminMonitor/message_sr.properties +++ /dev/null @@ -1,19 +0,0 @@ -# This file is under the MIT License by authors - -pleaseRekeyAsap=\ - Због отривене рањивости, морамо \ - променити кључ за шифровање тајни да диску. \ - Тај процес претражи велики део вашег $JENKINS_HOME ({0}) директоријума, \ - и поново изграчуна хеш за пронађене податке, што може прилично дуго трајати. \ - Прочитајте овај документ где се пише о више импликација и другачије начине \ - Ова операција се може безбедно извршити у позадини, међутим обазриви корисници \ - би могли направити резервне копије подацима. - -rekeyInProgress=Поново хеширање је у току. Можете прегледајти журнал. - -rekeySuccessful=\ - Secrets in your $JENKINS_HOME је успешно изхеширано. \ - Молимо прегледајте журнал, потврдите, и наставите или поново извршите. - -rekeyHadProblems=\ - Поново хеширање је готово, међутим било је грешака. Молимо прегледајте журнал. diff --git a/core/src/main/resources/jenkins/security/RekeySecretAdminMonitor/message_sv_SE.properties b/core/src/main/resources/jenkins/security/RekeySecretAdminMonitor/message_sv_SE.properties deleted file mode 100644 index db8387935c..0000000000 --- a/core/src/main/resources/jenkins/security/RekeySecretAdminMonitor/message_sv_SE.properties +++ /dev/null @@ -1,16 +0,0 @@ -pleaseRekeyAsap=\ - På grund av en säkerhetsrisk som upptäcktes tidigare måste vi \ - ändra krypteringsnyckeln som används för att skydda hemligheter i dina konfigurationsfiler på disken. \ - Denna process skannar en stor del av din $JENKINS_HOME ({0}) \ - för att hitta krypterad data och tilldela nya nycklar, vilket kommer att ta en stund. \ - Se det här dokumentet för fler implikationer om olika sätt att göra (eller inte göra) \ - detta. Denna åtgärd är säker att köras i bakgrunden, men försiktiga användare rekommenderas att göra säkerhetskopior. - -rekeyInProgress=Nya nycklar tilldelas. Visa loggen. - -rekeySuccessful=\ - Hemligheter i din $JENKINS_HOME har fått nya nycklar. \ - Visa loggen, bekräfta resultatet och sedan avfärda eller kör igen. - -rekeyHadProblems=\ - Nya nycklar har tilldelats, men problem uppstod. Visa loggen. diff --git a/core/src/main/resources/jenkins/security/RekeySecretAdminMonitor/message_zh_TW.properties b/core/src/main/resources/jenkins/security/RekeySecretAdminMonitor/message_zh_TW.properties deleted file mode 100644 index 0a5da78c91..0000000000 --- a/core/src/main/resources/jenkins/security/RekeySecretAdminMonitor/message_zh_TW.properties +++ /dev/null @@ -1,42 +0,0 @@ -# The MIT License -# -# Copyright (c) 2013, Chunghwa Telecom Co., Ltd., Pei-Tang Huang -# -# 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. - -pleaseRekeyAsap=\ - 為了修正先前發現的安全性弱點,\ - 用來保護磁碟上含機敏設定檔的加密金鑰一定要更改。\ - 整個程序會掃描您 $JENKINS_HOME ({0}) 中的大部分檔案,找出加密的資料重套金鑰,可能要花上不少時間。\ - 這份文件說明了實施 (或什麼事都不做) 這項措施的方法及影響。\ - 這項作業可以安全的在背景執行,不過如果您很謹慎,建議您先做好備份。 - -rekeyInProgress=金鑰重套中。您可以查看記錄。 - -rekeySuccessful=\ - 您 $JENKINS_HOME 中的機敏檔案重套金鑰成功。\ - 請查看記錄,確認是否真的成功,再決定要略過或是重跑一次。 - -rekeyHadProblems=\ - 金鑰重套完成,但是遇到一些問題。請查看記錄。 - -Re-key\ in\ background\ now=馬上在背景重套金鑰 -Re-keying\ currently\ scheduled\ during\ the\ next\ startup=已經排定在下次啟動後重套金鑰 -Schedule\ a\ re-key\ during\ the\ next\ startup=排程在下次啟動後重套金鑰 -Dismiss\ this\ message=忽略這個訊息 diff --git a/core/src/test/java/hudson/util/SecretRewriterTest.java b/core/src/test/java/hudson/util/SecretRewriterTest.java deleted file mode 100644 index 4c13761a4c..0000000000 --- a/core/src/test/java/hudson/util/SecretRewriterTest.java +++ /dev/null @@ -1,112 +0,0 @@ -package hudson.util; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assume.assumeFalse; - -import hudson.FilePath; -import hudson.Functions; -import hudson.model.TaskListener; -import java.io.File; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Base64; -import java.util.List; -import java.util.regex.Pattern; -import javax.crypto.Cipher; -import jenkins.security.ConfidentialStoreRule; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; - -public class SecretRewriterTest { - - @Rule - public ConfidentialStoreRule confidentialStoreRule = new ConfidentialStoreRule(); - - @Rule - public TemporaryFolder tmp = new TemporaryFolder(); - - private static final Pattern FOO_PATTERN = Pattern.compile("[{][A-Za-z0-9+/]+={0,2}[}]"); - private static final Pattern MSG_PATTERN = Pattern.compile("[{][A-Za-z0-9+/]+={0,2}[}]"); - private static final Pattern FOO_PATTERN2 = Pattern.compile("([{][A-Za-z0-9+/]+={0,2}[}]){2}"); - private static final Pattern ABC_FOO_PATTERN = Pattern.compile("\\s[{][A-Za-z0-9+/]+={0,2}[}]\\s"); - - @Test - public void singleFileRewrite() throws Exception { - String o = encryptOld("foobar"); // old - String n = encryptNew("foobar"); // new - assertTrue(FOO_PATTERN.matcher(roundtrip("" + o + "")).matches()); - assertTrue(FOO_PATTERN2.matcher(roundtrip("" + o + "" + o + "")).matches()); - assertEquals("" + n + "", roundtrip("" + n + "")); - assertEquals("thisIsLegalBase64AndLongEnoughThatItCouldLookLikeSecret", roundtrip(" thisIsLegalBase64AndLongEnoughThatItCouldLookLikeSecret ")); - // to be rewritten, it needs to be between a tag - assertEquals("" + o, roundtrip("" + o)); - assertEquals(o + "", roundtrip(o + "")); - assertTrue(ABC_FOO_PATTERN.matcher(roundtrip("\n" + o + "\n")).matches()); - } - - private String roundtrip(String before) throws Exception { - SecretRewriter sr = new SecretRewriter(); - Path path = Files.createTempFile(tmp.getRoot().toPath(), "test", "xml"); - Files.writeString(path, before, Charset.defaultCharset()); - sr.rewrite(path.toFile()); - //assert after.replaceAll(System.getProperty("line.separator"), "\n").trim()==f.text.replaceAll(System.getProperty("line.separator"), "\n").trim() - return Files.readString(path, Charset.defaultCharset()).replaceAll(System.lineSeparator(), "\n").trim(); - } - - @SuppressWarnings("deprecation") - private String encryptOld(String str) throws Exception { - Cipher cipher = Secret.getCipher("AES"); - cipher.init(Cipher.ENCRYPT_MODE, HistoricalSecrets.getLegacyKey()); - return Base64.getEncoder().encodeToString(cipher.doFinal((str + HistoricalSecrets.MAGIC).getBytes(StandardCharsets.UTF_8))); - } - - private String encryptNew(String str) { - return Secret.fromString(str).getEncryptedValue(); - } - - /** - * Directory rewrite and recursion detection - */ - @Test - public void recursionDetection() throws Exception { - assumeFalse("Symlinks don't work on Windows very well", Functions.isWindows()); - SecretRewriter sw = new SecretRewriter(); - TaskListener st = StreamTaskListener.fromStdout(); - - String o = encryptOld("Hello world"); - String n = encryptNew("Hello world"); - String payload = "" + o + ""; - - // set up some directories with stuff - File t = tmp.newFolder("t"); - List dirs = List.of("a", "b", "c", "c/d", "c/d/e"); - for (String p : dirs) { - File d = new File(t, p); - d.mkdir(); - Files.writeString(d.toPath().resolve("foo.xml"), payload, Charset.defaultCharset()); - } - - // stuff outside - File t2 = tmp.newFolder("t2"); - Files.writeString(t2.toPath().resolve("foo.xml"), payload, Charset.defaultCharset()); - - // some recursions as well as valid symlinks - new FilePath(t).child("c/symlink").symlinkTo("..", st); - new FilePath(t).child("b/symlink").symlinkTo(".", st); - new FilePath(t).child("a/symlink").symlinkTo(t2.getAbsolutePath(), st); - - assertEquals(6, sw.rewriteRecursive(t, st)); - - for (String p : dirs) { - assertTrue(MSG_PATTERN.matcher(Files.readString(new File(t, p + "/foo.xml").toPath(), Charset.defaultCharset()).trim()).matches()); - } - - // t2 is only reachable by following a symlink. this should be covered, too - assertTrue(MSG_PATTERN.matcher(Files.readString(new File(t2, "foo.xml").toPath(), Charset.defaultCharset()).trim()).matches()); - } - -} diff --git a/test/src/test/java/jenkins/security/RekeySecretAdminMonitorTest.java b/test/src/test/java/jenkins/security/RekeySecretAdminMonitorTest.java deleted file mode 100644 index c04c2a1c89..0000000000 --- a/test/src/test/java/jenkins/security/RekeySecretAdminMonitorTest.java +++ /dev/null @@ -1,189 +0,0 @@ -package jenkins.security; - -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.RetentionPolicy.RUNTIME; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertThrows; -import static org.junit.Assert.assertTrue; - -import hudson.ExtensionList; -import hudson.FilePath; -import hudson.Util; -import hudson.util.Secret; -import hudson.util.SecretHelper; -import java.io.File; -import java.io.IOException; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Base64; -import java.util.regex.Pattern; -import java.util.stream.Stream; -import javax.crypto.Cipher; -import org.hamcrest.MatcherAssert; -import org.hamcrest.Matchers; -import org.htmlunit.ElementNotFoundException; -import org.htmlunit.html.DomNodeUtil; -import org.htmlunit.html.HtmlButton; -import org.htmlunit.html.HtmlForm; -import org.htmlunit.html.HtmlPage; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.jvnet.hudson.test.JenkinsRecipe; -import org.jvnet.hudson.test.JenkinsRule; -import org.xml.sax.SAXException; - -/** - * @author Kohsuke Kawaguchi - */ -public class RekeySecretAdminMonitorTest { - - @Rule public JenkinsRule j = new JenkinsRule(); - - RekeySecretAdminMonitor monitor; - - final String plain_regex_match = ".*\\{[A-Za-z0-9+/]+={0,2}}.*"; - - @Before - public void setUp() { - monitor = ExtensionList.lookupSingleton(RekeySecretAdminMonitor.class); - } - - @JenkinsRecipe(RekeySecretAdminMonitorTest.WithTestSecret.RuleRunnerImpl.class) - @Target(METHOD) - @Retention(RUNTIME) - public @interface WithTestSecret { - class RuleRunnerImpl extends JenkinsRecipe.Runner { - @Override - public void setup(JenkinsRule jenkinsRule, WithTestSecret recipe) { - SecretHelper.set(TEST_KEY); - } - - @Override - public void tearDown(JenkinsRule jenkinsRule, WithTestSecret recipe) { - SecretHelper.set(null); - } - } - } - - @JenkinsRecipe(RekeySecretAdminMonitorTest.WithScanOnBoot.RuleRunnerImpl.class) - @Target(METHOD) - @Retention(RUNTIME) - public @interface WithScanOnBoot { - class RuleRunnerImpl extends JenkinsRecipe.Runner { - @Override - public void decorateHome(JenkinsRule jenkinsRule, File home) throws Exception { - // schedule a scan on boot - File f = new File(home, RekeySecretAdminMonitor.class.getName() + "/scanOnBoot"); - f.getParentFile().mkdirs(); - new FilePath(f).touch(0); - - // and stage some data - putSomeOldData(home); - } - } - } - - private static void putSomeOldData(File dir) throws Exception { - File xml = new File(dir, "foo.xml"); - Files.writeString(xml.toPath(), "" + encryptOld(TEST_KEY) + "", StandardCharsets.UTF_8); - } - - private void verifyRewrite(File dir) throws Exception { - Path xml = dir.toPath().resolve("foo.xml"); - Pattern pattern = Pattern.compile("" + plain_regex_match + ""); - MatcherAssert.assertThat(Files.readString(xml, StandardCharsets.UTF_8).trim(), Matchers.matchesRegex(pattern)); - } - - @WithTestSecret - @Test - public void testBasicWorkflow() throws Exception { - putSomeOldData(j.jenkins.getRootDir()); - monitor.setNeeded(); - - JenkinsRule.WebClient wc = j.createWebClient(); - - // one should see the warning. try scheduling it - assertFalse(monitor.isScanOnBoot()); - HtmlForm form = getRekeyForm(wc); - j.submit(form, "schedule"); - assertTrue(monitor.isScanOnBoot()); - form = getRekeyForm(wc); - assertTrue(getButton(form, 1).isDisabled()); - - // run it now - assertFalse(monitor.getLogFile().exists()); - j.submit(form, "background"); - assertTrue(monitor.getLogFile().exists()); - - // should be no warning/error now - HtmlPage manage = wc.goTo("manage"); - assertEquals(0, DomNodeUtil.selectNodes(manage, "//*[class='error']").size()); - assertEquals(0, DomNodeUtil.selectNodes(manage, "//*[class='warning']").size()); - - // and the data should be rewritten - verifyRewrite(j.jenkins.getRootDir()); - assertTrue(monitor.isDone()); - - // dismiss and the message will be gone - assertTrue(monitor.isEnabled()); - form = getRekeyForm(wc); - j.submit(form, "dismiss"); - assertFalse(monitor.isEnabled()); - assertThrows(ElementNotFoundException.class, () -> getRekeyForm(wc)); - } - - private HtmlForm getRekeyForm(JenkinsRule.WebClient wc) throws IOException, SAXException { - return wc.goTo("manage").getFormByName("rekey"); - } - - private HtmlButton getButton(HtmlForm form, int index) { - // due to the removal of method HtmlElement.getHtmlElementsByTagName - Stream buttonStream = form.getElementsByTagName("button").stream() - .filter(HtmlButton.class::isInstance) - .map(HtmlButton.class::cast); - - if (index > 0) { - buttonStream = buttonStream.skip(index); - } - - return buttonStream - .findFirst() - .orElse(null); - } - - @WithTestSecret - @WithScanOnBoot - @Test - public void testScanOnBoot() throws Exception { - JenkinsRule.WebClient wc = j.createWebClient(); - - // scan on boot should have run the scan - assertTrue(monitor.getLogFile().exists()); - assertFalse("scan on boot should have turned this off", monitor.isScanOnBoot()); - - // and data should be migrated - verifyRewrite(j.jenkins.getRootDir()); - - // should be no warning/error now - HtmlPage manage = wc.goTo("manage"); - assertEquals(0, DomNodeUtil.selectNodes(manage, "//*[class='error']").size()); - assertEquals(0, DomNodeUtil.selectNodes(manage, "//*[class='warning']").size()); - } - - private static String encryptOld(String str) throws Exception { - Cipher cipher = Secret.getCipher("AES"); - cipher.init(Cipher.ENCRYPT_MODE, Util.toAes128Key(TEST_KEY)); - return Base64.getEncoder().encodeToString(cipher.doFinal((str + "::::MAGIC::::").getBytes(StandardCharsets.UTF_8))); - } - - private String encryptNew(String str) { - return Secret.fromString(str).getEncryptedValue(); - } - - private static final String TEST_KEY = "superDuperSecretWasNotSoSecretAfterAll"; -}