Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[JENKINS-41952] mismatch on the encoding of the keystore: sometimes a…
…s “Secret(base64(keystore))” and sometimes as “new SecretBytes(keystore).toString()”
  • Loading branch information
cyrille-leclerc committed Feb 14, 2017
1 parent 03b497e commit 70d44d2
Showing 1 changed file with 38 additions and 5 deletions.
Expand Up @@ -31,6 +31,7 @@
import com.trilead.ssh2.crypto.Base64;
import edu.umd.cs.findbugs.annotations.CheckForNull;
import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.Nullable;
import hudson.Extension;
import hudson.Util;
import hudson.model.AbstractDescribableImpl;
Expand Down Expand Up @@ -305,6 +306,10 @@ protected KeyStoreSourceDescriptor(Class<? extends KeyStoreSource> clazz) {
protected static FormValidation validateCertificateKeystore(String type, byte[] keystoreBytes,
String password) {

if (keystoreBytes == null || keystoreBytes.length == 0) {
return FormValidation.warning(Messages.CertificateCredentialsImpl_LoadKeystoreFailed());
}

char[] passwordChars = toCharArray(Secret.fromString(password));
try {
KeyStore keyStore = KeyStore.getInstance(type);
Expand Down Expand Up @@ -594,10 +599,12 @@ public static class DescriptorImpl extends KeyStoreSourceDescriptor {
* @return the keystore bytes.
* @see #toSecret(byte[])
*/
public static byte[] toByteArray(Secret secret) {
@NonNull
public static byte[] toByteArray(@Nullable Secret secret) {
if (secret != null) {
try {
return Base64.decode(secret.getPlainText().toCharArray());
String plainText = secret.getPlainText();
return Base64.decode(plainText.toCharArray());
} catch (IOException e) {
// ignore
}
Expand All @@ -612,7 +619,8 @@ public static byte[] toByteArray(Secret secret) {
* @return the keystore as a secret.
* @see #toByteArray(Secret)
*/
public static Secret toSecret(byte[] contents) {
@CheckForNull
public static Secret toSecret(@Nullable byte[] contents) {
return contents == null || contents.length == 0
? null
: Secret.fromString(new String(Base64.encode(contents)));
Expand Down Expand Up @@ -640,7 +648,30 @@ public FormValidation doCheckUploadedKeystore(@QueryParameter String value,
if (StringUtils.isBlank(value)) {
return FormValidation.error(Messages.CertificateCredentialsImpl_NoCertificateUploaded());
}
return validateCertificateKeystore("PKCS12", toByteArray(Secret.fromString(value)), password);
byte[] keystoreBytes;

// JENKINS-41946: value can have 2 different formats
if (value.startsWith("{") && value.endsWith("}")) {
// JENKINS-41946 when displaying credentials based on an uploaded keystore,
// doCheckUploadedKeystore() is called with value=Secret.fromString(Base64(keystore))
// see com.cloudbees.plugins.credentials.impl.CertificateCredentialsImpl.UploadedKeyStoreSource.Upload.doUpload()
SecretBytes secretBytes = SecretBytes.fromString(value);
keystoreBytes = secretBytes.getPlainData();
if (keystoreBytes == null || keystoreBytes.length == 0) {
return FormValidation.error(Messages.CertificateCredentialsImpl_LoadKeystoreFailed());
}
} else {
// JENKINS-41946 when uploading a new keystore,
// doCheckUploadedKeystore() is called with value=SecretBytes.toString()
// see com.cloudbees.plugins.credentials.impl.CertificateCredentialsImpl.UploadedKeyStoreSource.getUploadedKeystore()
Secret secret = Secret.fromString(value);
keystoreBytes = toByteArray(secret);
if (keystoreBytes == null || keystoreBytes.length == 0) {
return FormValidation.error(Messages.CertificateCredentialsImpl_LoadKeystoreFailed());
}
}

return validateCertificateKeystore("PKCS12", keystoreBytes, password);
}

/**
Expand Down Expand Up @@ -728,8 +759,10 @@ public HttpResponse doUpload(@NonNull StaplerRequest req) throws ServletExceptio
// view for that instance. The "complete" view can then do the injection and close itself so that
// the user experience is the pop-up then click upload and finally we inject back in the content to
// the form.
// TODO JENKINS-41946: uploadedKeystore should probably be converted to a SecretBytes instead of being converted to a Secret
Secret uploadedKeystore = DescriptorImpl.toSecret(file.get());
return HttpResponses.forwardToView(
new Upload(getDivId(), UploadedKeyStoreSource.DescriptorImpl.toSecret(file.get())), "complete");
new Upload(getDivId(), uploadedKeystore), "complete");
}
}
}
Expand Down

0 comments on commit 70d44d2

Please sign in to comment.