Skip to content

Commit e0f83ed

Browse files
[JENKINS-75905] Include update site URL in signature verification in error messages (#25980)
* [JENKINS-75905] Include update site URL in signature verification error messages * [JENKINS-75905] Include update site URL in signature verification error messages * [JENKINS-75905] Include update site URL in signature verification error messages * Use the non-deprecated getJsonSignatureValidator method and add @nonnull annotation Use the non-deprecated getJsonSignatureValidator Add @nonnull annotation to the Throwable parameter in JSONSignatureValidator#getRootCauseMessage. * Test both branches of message formatter --------- Co-authored-by: Mark Waite <[email protected]>
1 parent 474f2aa commit e0f83ed

File tree

5 files changed

+126
-2
lines changed

5 files changed

+126
-2
lines changed

core/src/main/java/hudson/model/UpdateSite.java

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,29 @@ protected UpdateCenter.InstallationJob createInstallationJob(Plugin plugin, Upda
294294
*/
295295
@Restricted(NoExternalUse.class)
296296
public final FormValidation verifySignatureInternal(JSONObject o) throws IOException {
297-
return getJsonSignatureValidator().verifySignature(o);
297+
FormValidation result = getJsonSignatureValidator(null).verifySignature(o);
298+
299+
if (result.kind == FormValidation.Kind.ERROR) {
300+
String message = result.getMessage();
301+
if (message != null) {
302+
// String siteUrl = getUrl();
303+
String updatedMessage;
304+
305+
if (message.contains("update site") && message.contains(" Path") && !message.contains(url)) {
306+
// Ensure the update site URL is included in error messages by replacing the site identifier in messages of the 'update site … Path' pattern or appending it otherwise.
307+
updatedMessage = message.replaceAll(
308+
"(update site\\s+).*?(\\s+Path)",
309+
"$1" + url + "$2"
310+
);
311+
} else {
312+
// Do not alter message structure; only add URL context
313+
updatedMessage = message + " (URL: " + url + ")";
314+
}
315+
return FormValidation.error(updatedMessage);
316+
}
317+
}
318+
319+
return result;
298320
}
299321

300322
/**

core/src/main/java/jenkins/util/JSONSignatureValidator.java

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package jenkins.util;
22

3+
import edu.umd.cs.findbugs.annotations.NonNull;
34
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
45
import hudson.Util;
56
import hudson.util.FormValidation;
@@ -138,7 +139,9 @@ public FormValidation verifySignature(JSONObject o) throws IOException {
138139
if (warning != null) return warning;
139140
return FormValidation.ok();
140141
} catch (GeneralSecurityException e) {
141-
return FormValidation.error(e, "Signature verification failed in " + name);
142+
// Return a user-friendly error message without the full stack trace
143+
String rootCauseMessage = getRootCauseMessage(e);
144+
return FormValidation.error("Signature verification failed in " + name + ": " + rootCauseMessage);
142145
}
143146
}
144147

@@ -321,5 +324,25 @@ protected Set<TrustAnchor> loadTrustAnchors(CertificateFactory cf) throws IOExce
321324
return anchors;
322325
}
323326

327+
/**
328+
* Extracts a user-friendly message from an exception chain.
329+
*
330+
* @param e the exception to extract the message from
331+
* @return a concise, readable error message
332+
*/
333+
private String getRootCauseMessage(@NonNull Throwable e) {
334+
Throwable cause = e;
335+
while (cause.getCause() != null && cause.getCause() != cause) {
336+
cause = cause.getCause();
337+
}
338+
339+
String message = cause.getMessage();
340+
if (message != null && !message.isEmpty()) {
341+
return message;
342+
}
343+
344+
return cause.getClass().getSimpleName();
345+
}
346+
324347
private static final Logger LOGGER = Logger.getLogger(JSONSignatureValidator.class.getName());
325348
}

test/src/test/java/hudson/model/UpdateSiteTest.java

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424

2525
package hudson.model;
2626

27+
import static org.hamcrest.MatcherAssert.assertThat;
28+
import static org.hamcrest.Matchers.containsString;
2729
import static org.junit.jupiter.api.Assertions.assertEquals;
2830
import static org.junit.jupiter.api.Assertions.assertFalse;
2931
import static org.junit.jupiter.api.Assertions.assertNotEquals;
@@ -299,4 +301,45 @@ private PluginWrapper buildPluginWrapper(String name, String wikiUrl) {
299301
new ArrayList<>()
300302
);
301303
}
304+
305+
@Test
306+
void signatureVerificationFailureIncludesUpdateSiteUrl() throws Exception {
307+
// Create an UpdateSite with an invalid/malformed signature that will trigger an error
308+
URL url = new URL(baseUrl, "/plugins/invalid-signature-update-center.json");
309+
UpdateSite site = new UpdateSite(UpdateCenter.ID_DEFAULT, url.toString());
310+
overrideUpdateSite(site);
311+
312+
FormValidation validation = site.updateDirectlyNow(true);
313+
314+
assertEquals(FormValidation.Kind.ERROR, validation.kind);
315+
316+
String message = validation.getMessage();
317+
assertNotNull(message);
318+
assertTrue(
319+
message.contains(url.toString()),
320+
"Signature verification error should include update site URL"
321+
);
322+
assertThat(message, containsString("Empty input"));
323+
}
324+
325+
@Test
326+
void signatureVerificationFailureIncludesUpdateSiteUrlWithoutPath() throws Exception {
327+
// Create an UpdateSite with an invalid/malformed signature that will trigger an error that involves Path
328+
URL url = new URL(baseUrl, "/plugins/invalid-signature-update-center-core-cm.json");
329+
UpdateSite site = new UpdateSite(UpdateCenter.ID_DEFAULT, url.toString());
330+
overrideUpdateSite(site);
331+
332+
FormValidation validation = site.updateDirectlyNow(true);
333+
334+
assertEquals(FormValidation.Kind.ERROR, validation.kind);
335+
336+
String message = validation.getMessage();
337+
assertNotNull(message);
338+
assertTrue(
339+
message.contains(url.toString()),
340+
"Signature verification error should include update site URL"
341+
);
342+
assertThat(message, containsString("Path does not chain with any of the trust anchors"));
343+
}
344+
302345
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"updateCenterVersion": 1,
3+
"core": {
4+
"name": "core",
5+
"version": "2.541",
6+
"url": "http://updates.jenkins.io/download/war/2.541/jenkins.war"
7+
},
8+
"plugins": {},
9+
"signature": {
10+
"correct_digest": "scNImoAz/AONJTUC+jwpX1ik1Mg=",
11+
"correct_digest512": "0442f8003c5b707bdd7f8f06c096d51c3da1ad5715946ad226a8e4c8ce85a71a4db1cf4f7bf9565220a7339a2103780ae75e85a08c18e9642165c9f296660e56",
12+
"certificates": [
13+
"MIIFhDCCA2wCCQDGSFE7A358zjANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkRFMRgwFgYDVQQKDA9DbG91ZEJlZXMsIEluYy4xFjAUBgNVBAMMDXVwZGF0ZS1jZW50ZXIxNTAzBgkqhkiG9w0BCQEWJm9wZXJhdGlvbnMrdXBkYXRlLWNlbnRlckBjbG91ZGJlZXMuY29tMB4XDTIwMDUyOTAxMjgxNFoXDTMwMDUyNzAxMjgxNFowgYMxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJERTEYMBYGA1UECgwPQ2xvdWRCZWVzLCBJbmMuMRYwFAYDVQQDDA11cGRhdGUtY2VudGVyMTUwMwYJKoZIhvcNAQkBFiZvcGVyYXRpb25zK3VwZGF0ZS1jZW50ZXJAY2xvdWRiZWVzLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAJyeG1X+jhC6NdNTyYRP0iPBF8j1gt9BGsGfTktdwpHpHSfHWwn2S3SAkAGVpck6kOWudejHvKmaAHMEiON0T4RHLnOc0BRd5W/BOzyVgB0eytkjSANeB9UIRNuCZoUM8NdNCyAcr9fmsns6jVRzCwnuyxeXFvGYgikzoO/ZC0/vsyAHp/2AzvgTE/7tFuJYHuvQ8ACfSPRgSQ3rc0hpSnSVV1UqTwrE/1AIhEjisNRXc6eMxlStFIsVuRkdaJRr7pi6W0mFmQr2gFtDHJkqX2nwHqNPzuJ7AVF2VXlh4j7GecDxwVdtVKdQEuCxn7IbX8UbWLcA/IwBnR8ZaHUr1KER+LjTIjwXlQnv3wAoz3YqCvgvKlx1HVTtf/PVlJG0STiPHZtwSqJpgXjQ+XLXCW1gsevDR2fyyddxC5p21AvQ480SGY1cRuesTEpoZjTYW4jNJsb8JKhyyAM50GHYWIgCyCavgHH+da+J7kgSqVmBIgum9Ws4Mh6AQHTUcxozff3vIUnRU8B5Lg20q4UZqDrFHKxQMyvEFXBmGIsqw6EtPTKzPWIq/noq2YT4mrpi1iFDPd8phHuy7IIDqmHPP0GvcL9f/QUDysmVgOuOQShtFhA5ZX2KHJ4sjtPDzYq/EjStI+tytR10aV12a/iL4eBfNlhP0UiPVhw2hLg3xMLBAgMBAAEwDQYJKoZIhvcNAQELBQADggIBAHGSLYRRZ032pmbwHY8yg9+z7P2TljaYA4dI5/WUmev0oNyEwEwcbMhhLq1yIG9bDjo65WFYyNijX7eJHGSTR2clRLRZ67N2z4hOkymgLbpXgCoyAr7Pgkl2sxz3lW/VPTN7ZFl37ZkbsUuSFy5BnNXkISh5bDATX9JCJCPYzdVKBbjd2kyMeiOz7Gf/SYOEBvp/vgz3gqv5ZLQIEKFmZT2imiELmfgO0uuVlCgJWU9PDGEb2MW4Td0v0hzL5aycYQSl0bAbiTSqofSIOUdniELYJEtn0G/tdxY5ZnlgEP8jdSNlsnESArjyxGJanwxzQdMps6MaTxew+tYPzjMACEQaLeNUHmLtlMRFaqWPcOj85XZ3qzBwwOESFq3NQu8NZcOJrNr84AHFkPnE90gSNaZlA2XJReioGViBmo421LypKobjbny0z2L2jvQ7lI23Hdt4DA34cB6dlPg/6Vi9PyhokeNTL5VZCGpU8WzhMoxq/4pNLawq2suE92OeYuWDz2v65OJWJe1EEXQhX5H8G1001pv2OD+p5xew/QfDxshCsi3hPVRSB1qVquMgmhOBCnq1j/ocGOubLKQ0WpeSUYDynVrfpvQ1rCW+Sbz0fEduMPrD8c+2+v/U6NFDxqZCtooRbtNQeKuyJYtKoB6VuUAWHOqi95lCirlplY2Mjljn"
14+
],
15+
"correct_signature": "ZDSVZkFRPiIbwDkpwfj0B3B/PvGc5mNpNvR6tcxCn2LKDWKeYXu/MJzsna+3ElohT+QXzzvKvw5oiAkhvTQ0l9o/jOhBzMiS8dYl6uVebdb70DVgoLrNe02DqxXoMTkXLOnZ/tpGRrWxPhi2dMy6bUt5aBl6gGbiog3OSlA+TafO/KH4yxK5/0cv8kfUW3c6HopY5rRq4z6RUXTPaljO1iVE91w3QYrDahhHBBC3UPetfslEWSliTgckUFojfdX/67hR1921lgL2ITxGtOS4j+dO9ydUVAaY6McAU1kJVrljY9IwsLxMaENrAL7otXG2xKBBCskTNcrizODuyzIg7LHOOVX6/EIzTN+o9RZG4b5zxwQZq5NS4yldbPpXPZuXnezCWr8qndwK3pqbiwmvLiBcsFCrnz7e2ixiAs7c6ZY6srb5WScVywZeLHwhpISEBPZe4ejvWQRHaDanca15IKeqARJKL8H/Jti1aUHqrLkH92s8FWaEL25TrMXb5u2r15qpL6OCMP+5O2jEnVl0ajkkNb/BBqUPuPXsg5vo8tkuk7gylNrK0LSM/t49gdYGBE/Cp2GgvGwfhasM27Os+J1TnIs0Bqsl125CwWxa7aXql39JQ/t12ekAUZvgziTGY1LHO4V7YMWTdiBdr57LKudFpFJZGXsPMkupi8mtlCU=",
16+
"correct_signature512": "0403e57342c6610922a4ca1c647b075923baa9d38ba50a9b5eb3fd2cd4154febf60434d3d9dc2e15db536128191f69a0bafe119cba7b7d887b8b0d38ebac0855da7b6f958afe06a48362cee018159628852fa593e58e56aa8cf94c978f344e906db8559b69d72971b918322e7108a23fb124022b2f442f73f12e5a34af0385295954f7347da4ff0faf33db8c2dc1c1684551a0018c30fd2d39117717b092c42e20c6d78506d89d942d30c66295c5e04cfd655259e4a4a263a85a7b3a89377ae067279989a164ab46ae34edbed7f722f3c4f2bbd9d59412559eeaed03ef5e743602c54d0222d010ce0c010576a682b9979654e976aa418deb0de5069139031e04a61d26904e70bdca2168dc434f5955c6f39f6c6fe45b6014702b5afedfa2f89763f2e43fbb82d47858a1fd0bd04bea05a4f23d207d28c3246a99c2b2ac84a4fa16da292148074afd358728a2844ef985bf9a1479d6cf1bb1d7acc48c9731e2a9906f8beac110d91c851736bfd12508ae08c669d89a74a347a764b1f4be5fe01829ab0f80e6da5e2abafeb045a50b066ec3d6a6a95254fdc57e898eaf91b48d8585ef74b9ab1feecea2583c37be77d7c295c5918d492e01515b76877508d8af3bedddf1f2c56453ffa88505df9b2d8865e5a9970af0875cbfa596afe10326befbea4970cb2160b59cbff683b351d0a3b872039934cfff668dfe92c3f4d4abd262",
17+
"digest": "216DEgEmoe6+B+96+1RFOIKCqmY=",
18+
"signature": "X4RsFd2sxBMy2BaUeW64hvzP+VUg/nS0KSoKnCo26nt5G5qXvJ9TVb9ifMuLdFnk2kPMGOh/NZ5rfPFdVhLPRkcpg9saAXYcMYj4Nfg6gzlgBjsGzcmaQ6ky2q2qTIEXGZcjKTql99uap9hMXKaXDdgcfVE22mV92dvASazz1KX3fM37sticmC6eJF+Fj1OFx2BPjzPaNKZyXuwqMe7X3SG70fY0bbcc6TfOXSHWOI3WS0T7N13Br0cD/kx+r8sKDv73kkx/anI0VxxaGXcttZ9M9q/ubqRDju6dLubXP+5rTzQmphpwwUPz4t4mv0Acp8/E35Rp5SELn45cUJTyb2anxPOVB84gKBaeN9G+fitEmQkEt2jLnidcKTbNfgPUXWAkUnCuPbl7W7zeRQ4dnEQoCfkswS3Q5qoE8R0d76G//R8p6oeQZL9akV4NHV9E22iu0l+eA8GTrX50TEApF1+iil/Y4CeHWyALBn/FYARig2L3W040O9GOPoBGpZ5qTFxA55es4h69ij84nt+uANJzypzRFV7DmhL97UKm4XV7ADB+UQ90pXvAoih510O0p1/67xdZcKx5URhmj53xOAn8WbvATzeu8/MqNnglmTcX+VKInVWjai4gtOg2UmaijUCt0CuCcLNyWpClk51p0Kfr7gYb4UKJuWSIfVzHaPY="
19+
}
20+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"updateCenterVersion": "1",
3+
"core": {
4+
"name": "core",
5+
"version": "2.541",
6+
"url": "http://updates.jenkins.io/download/war/2.541/jenkins.war"
7+
},
8+
"plugins": {},
9+
"signature": {
10+
"certificates": [
11+
"InvalidBase64CertificateDataThatWillFailValidation=="
12+
],
13+
"correct_digest": "invalid_digest_value",
14+
"correct_signature": "invalid_signature_value"
15+
}
16+
}

0 commit comments

Comments
 (0)