-
Notifications
You must be signed in to change notification settings - Fork 245
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #580 from Priya-CB/JENKINS-74964
[JENKINS-74964] Display error message when adding invalid certificate credentials
- Loading branch information
Showing
8 changed files
with
327 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -39,6 +39,7 @@ | |
import hudson.security.AccessControlled; | ||
import hudson.security.Permission; | ||
import java.io.IOException; | ||
import java.security.GeneralSecurityException; | ||
import java.util.ArrayList; | ||
import java.util.Collection; | ||
import java.util.HashSet; | ||
|
@@ -47,10 +48,14 @@ | |
import java.util.Map; | ||
import java.util.Set; | ||
import java.util.TreeMap; | ||
import java.util.logging.Level; | ||
import java.util.logging.Logger; | ||
|
||
import jakarta.servlet.ServletException; | ||
import jenkins.model.Jenkins; | ||
import net.sf.json.JSONObject; | ||
import org.apache.commons.lang.StringUtils; | ||
import org.apache.commons.lang.exception.ExceptionUtils; | ||
import org.jenkins.ui.icon.IconSpec; | ||
import org.kohsuke.accmod.Restricted; | ||
import org.kohsuke.accmod.restrictions.NoExternalUse; | ||
|
@@ -76,6 +81,8 @@ public class CredentialsSelectHelper extends Descriptor<CredentialsSelectHelper> | |
*/ | ||
public static final Permission CREATE = CredentialsProvider.CREATE; | ||
|
||
private static final Logger LOGGER = Logger.getLogger(CredentialsSelectHelper.class.getName()); | ||
|
||
/** | ||
* {@inheritDoc} | ||
Check warning on line 87 in src/main/java/com/cloudbees/plugins/credentials/CredentialsSelectHelper.java ci.jenkins.io / JavaDocJavaDoc @inheritDoc
|
||
*/ | ||
|
@@ -608,8 +615,34 @@ public JSONObject doAddCredentials(StaplerRequest2 req, StaplerResponse2 rsp) th | |
.element("notificationType", "ERROR"); | ||
} | ||
store.checkPermission(CredentialsStoreAction.CREATE); | ||
Credentials credentials = Descriptor.bindJSON(req, Credentials.class, data.getJSONObject("credentials")); | ||
boolean credentialsWereAdded = store.addCredentials(wrapper.getDomain(), credentials); | ||
boolean credentialsWereAdded; | ||
try { | ||
Credentials credentials = Descriptor.bindJSON(req, Credentials.class, | ||
data.getJSONObject("credentials")); | ||
credentialsWereAdded = store.addCredentials(wrapper.getDomain(), credentials); | ||
} catch (LinkageError e) { | ||
/* | ||
* Descriptor#newInstanceImpl throws a LinkageError if the DataBoundConstructor or any DataBoundSetter | ||
* throw any exception other than RuntimeException implementing HttpResponse. | ||
* | ||
* Checked exceptions implementing HttpResponse like FormException are wrapped and | ||
* rethrown as HttpResponseException (a RuntimeException implementing HttpResponse) in | ||
* RequestImpl#invokeConstructor. | ||
* | ||
* This approach is taken to maintain backward compatibility, as throwing a FormException directly | ||
* from the constructor would result in a source-incompatible change, potentially breaking dependent plugins. | ||
* | ||
* Here, known exceptions are caught specifically to provide meaningful error response. | ||
*/ | ||
Throwable rootCause = ExceptionUtils.getRootCause(e); | ||
if (rootCause instanceof IOException || rootCause instanceof IllegalArgumentException | ||
|| rootCause instanceof GeneralSecurityException) { | ||
LOGGER.log(Level.WARNING, "Failed to create Credentials", e); | ||
return new JSONObject().element("message", rootCause.getMessage()).element("notificationType", | ||
"ERROR"); | ||
} | ||
throw e; | ||
} | ||
if (credentialsWereAdded) { | ||
return new JSONObject() | ||
.element("message", "Credentials created") | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
86 changes: 86 additions & 0 deletions
86
src/test/java/com/cloudbees/plugins/credentials/impl/CertificateCredentialsImplFIPSTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
package com.cloudbees.plugins.credentials.impl; | ||
|
||
import java.io.IOException; | ||
import java.nio.charset.StandardCharsets; | ||
|
||
import org.apache.commons.io.IOUtils; | ||
import org.apache.commons.text.StringEscapeUtils; | ||
import org.junit.Before; | ||
import org.junit.Rule; | ||
import org.junit.Test; | ||
import org.junit.rules.TemporaryFolder; | ||
import org.jvnet.hudson.test.RealJenkinsRule; | ||
|
||
import hudson.ExtensionList; | ||
import hudson.util.FormValidation; | ||
|
||
import com.cloudbees.plugins.credentials.CredentialsScope; | ||
|
||
import static org.hamcrest.MatcherAssert.assertThat; | ||
import static org.hamcrest.Matchers.is; | ||
import static org.junit.Assert.assertThrows; | ||
|
||
public class CertificateCredentialsImplFIPSTest { | ||
|
||
@Rule | ||
public RealJenkinsRule rule = new RealJenkinsRule().withFIPSEnabled().javaOptions("-Xmx512m"); | ||
|
||
@Rule | ||
public TemporaryFolder tmp = new TemporaryFolder(); | ||
|
||
private String pemCert; | ||
private String pemKey; | ||
private static final String VALID_PASSWORD = "passwordFipsCheck"; | ||
private static final String INVALID_PASSWORD = "invalidPasswordFipsCheck"; | ||
private static final String SHORT_PASSWORD = "password"; | ||
|
||
@Before | ||
public void setup() throws IOException { | ||
pemCert = IOUtils.toString(CertificateCredentialsImplFIPSTest.class.getResource("validCerts.pem"), | ||
StandardCharsets.UTF_8); | ||
pemKey = IOUtils.toString(CertificateCredentialsImplFIPSTest.class.getResource("validKey.pem"), | ||
StandardCharsets.UTF_8); | ||
} | ||
|
||
@Test | ||
public void doCheckPasswordTest() throws Throwable { | ||
rule.then(r -> { | ||
CertificateCredentialsImpl.DescriptorImpl descriptor = ExtensionList.lookupSingleton( | ||
CertificateCredentialsImpl.DescriptorImpl.class); | ||
FormValidation result = descriptor.doCheckPassword(VALID_PASSWORD); | ||
assertThat(result.kind, is(FormValidation.Kind.OK)); | ||
result = descriptor.doCheckPassword(SHORT_PASSWORD); | ||
assertThat(result.kind, is(FormValidation.Kind.ERROR)); | ||
assertThat(result.getMessage(), | ||
is(StringEscapeUtils.escapeHtml4(Messages.CertificateCredentialsImpl_ShortPasswordFIPS()))); | ||
}); | ||
} | ||
|
||
@Test | ||
public void invalidPEMKeyStoreAndPasswordTest() throws Throwable { | ||
CertificateCredentialsImpl.PEMEntryKeyStoreSource storeSource = new CertificateCredentialsImpl.PEMEntryKeyStoreSource( | ||
pemCert, pemKey); | ||
rule.then(r -> { | ||
new CertificateCredentialsImpl(CredentialsScope.GLOBAL, "valid-certificate-and-password-validation", | ||
"Validate the certificate credentials", VALID_PASSWORD, storeSource); | ||
assertThrows(IllegalArgumentException.class, | ||
() -> new CertificateCredentialsImpl(CredentialsScope.GLOBAL, "empty-password-validation", | ||
"Validate the certificate empty password", "", | ||
storeSource)); | ||
assertThrows(IllegalArgumentException.class, | ||
() -> new CertificateCredentialsImpl(CredentialsScope.GLOBAL, "password-length-validation", | ||
"Validate the certificate password length", | ||
SHORT_PASSWORD, storeSource)); | ||
assertThrows(IllegalArgumentException.class, | ||
() -> new CertificateCredentialsImpl(CredentialsScope.GLOBAL, "invalid-password-validation", | ||
"Validate the certificate password", INVALID_PASSWORD, | ||
storeSource)); | ||
assertThrows(IllegalArgumentException.class, | ||
() -> new CertificateCredentialsImpl(CredentialsScope.GLOBAL, "empty-keystore-validation", | ||
"Validate the invalid certificate keyStore", | ||
VALID_PASSWORD, | ||
new CertificateCredentialsImpl.PEMEntryKeyStoreSource( | ||
null, null))); | ||
}); | ||
} | ||
} |
20 changes: 20 additions & 0 deletions
20
src/test/resources/com/cloudbees/plugins/credentials/impl/validCerts.pem
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
-----BEGIN CERTIFICATE----- | ||
MIIDUTCCAjmgAwIBAgIUM2p34T12bOzrnyga5GarEMbBI3QwDQYJKoZIhvcNAQEL | ||
BQAwUDELMAkGA1UEBhMCSU4xCzAJBgNVBAgMAlROMREwDwYDVQQHDAhUaXJ1cHB1 | ||
cjEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMCAXDTI0MTIxMjA5 | ||
NTgzM1oYDzIxMjQxMTE4MDk1ODMzWjBQMQswCQYDVQQGEwJJTjELMAkGA1UECAwC | ||
VE4xETAPBgNVBAcMCFRpcnVwcHVyMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRz | ||
IFB0eSBMdGQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCoI5pI11oR | ||
2nIvBMdViNN9RpztDYZuJ/tDl5JZz3jFHxwUFuneABMIqiySUFS3HK1Kfsz6Lvbz | ||
qZlLriE1cKKk84GBOlkpISaizAMUyYOkZagmVrsf/QrneLQdYjNZFpOjTCduWmsC | ||
3WLXWGA+t2qlT3jmJr+J5yyHBGme27dtab7UgoSdD2o0FFxXCG15NMkWMi+m+3zW | ||
UK9f4wmaY1wIBd3/umsHM1dv+vwqAfgMMp/I4ISTda2sm3txmDzYGBPzvc/bnsCe | ||
zyahE85Fi/otkqxqzDww2a7YhGY0hjcyihpqYffFw7zWo2syylLcFMFJN1nRoQyj | ||
lshfAeLcGYLHAgMBAAGjITAfMB0GA1UdDgQWBBSSmy62eRSGGzkJnFWrcJDoU3Za | ||
4jANBgkqhkiG9w0BAQsFAAOCAQEAW1YhiizwHdxIqf336vqk0Qn8omcg3v/GotjF | ||
hNqFHiCnr2Y1/+7NwqsvpIpjb354atU5nxJ1X1LkIJz/yPztbVbHzqKn/RUztSV6 | ||
+wCOArAZzTfXcgOf/jgqPRQMJxhtUeU01MKcoliBLzCIdYvNe3XdkjMkPUHxK5vt | ||
Yv5hxx+sfZ1T68xCFCgdkXtJKxkBDj9tR56vPOTN7kxpVPKFQzsI644xxID+JRbi | ||
RFwV8GYK8rF6nVw9EQAfi+PuJj+V8DecUshMy6d7heUKWdu5i/+HgVKx46/RZMkj | ||
gwAW4FDt8+qsdvgxYzCTkrkxbREwAtTv6xgPO2BAPZsECG/DSg== | ||
-----END CERTIFICATE----- |
Oops, something went wrong.