diff --git a/credentials-migration/export-credentials-folder-level.groovy b/credentials-migration/export-credentials-folder-level.groovy index 849127e..81687cf 100644 --- a/credentials-migration/export-credentials-folder-level.groovy +++ b/credentials-migration/export-credentials-folder-level.groovy @@ -18,8 +18,10 @@ import com.thoughtworks.xstream.io.HierarchicalStreamReader import com.thoughtworks.xstream.io.HierarchicalStreamWriter import com.trilead.ssh2.crypto.Base64 import hudson.util.Secret +import com.cloudbees.plugins.credentials.SecretBytes import hudson.util.XStream2 import jenkins.model.Jenkins +import java.nio.charset.StandardCharsets def instance = Jenkins.get() def credentials = [] @@ -61,14 +63,31 @@ def converter = new Converter() { @Override boolean canConvert(Class type) { type == Secret.class } } +// This converter ensure that the output XML contains base64 encoded for secretBytes (to handle FileCredentials) +def converterSecretBytes = new Converter() { + @Override + void marshal(Object object, HierarchicalStreamWriter writer, MarshallingContext context) { + writer.value = Base64.encode(new String(object.getPlainData(), StandardCharsets.UTF_8).bytes).toString();; + } + + @Override + Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { + return SecretBytes.fromBytes(new String(Base64.decode(reader.getValue().toCharArray())).getBytes(StandardCharsets.UTF_8)); + } + + @Override + boolean canConvert(Class type) { type == SecretBytes.class } +} def stream = new XStream2() stream.registerConverter(converter) +stream.registerConverter(converterSecretBytes) // Marshal the list of credentials into XML def encoded = [] - def xml = Base64.encode(stream.toXML(domainsFromFolders).bytes) - encoded.add("\"${xml}\"") +//println stream.toXML(domainsFromFolders); return ""; //For debug purpose +def xml = Base64.encode(stream.toXML(domainsFromFolders).bytes) +encoded.add("\"${xml}\"") println encoded.toString() \ No newline at end of file diff --git a/credentials-migration/export-credentials-system-level.groovy b/credentials-migration/export-credentials-system-level.groovy index 373c5c2..a40713f 100644 --- a/credentials-migration/export-credentials-system-level.groovy +++ b/credentials-migration/export-credentials-system-level.groovy @@ -17,8 +17,10 @@ import com.thoughtworks.xstream.io.HierarchicalStreamReader import com.thoughtworks.xstream.io.HierarchicalStreamWriter import com.trilead.ssh2.crypto.Base64 import hudson.util.Secret +import com.cloudbees.plugins.credentials.SecretBytes import hudson.util.XStream2 import jenkins.model.Jenkins +import java.nio.charset.StandardCharsets def instance = Jenkins.get() def credentials = [] @@ -48,11 +50,28 @@ def converter = new Converter() { @Override boolean canConvert(Class type) { type == Secret.class } } +// This converter ensure that the output XML contains base64 encoded for secretBytes (to handle FileCredentials) +def converterSecretBytes = new Converter() { + @Override + void marshal(Object object, HierarchicalStreamWriter writer, MarshallingContext context) { + writer.value = Base64.encode(new String(object.getPlainData(), StandardCharsets.UTF_8).bytes).toString(); + } + + @Override + Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { + return SecretBytes.fromBytes(new String(Base64.decode(reader.getValue().toCharArray())).getBytes(StandardCharsets.UTF_8)); + } + + @Override + boolean canConvert(Class type) { type == SecretBytes.class } +} def stream = new XStream2() stream.registerConverter(converter) +stream.registerConverter(converterSecretBytes) // Marshal the list of credentials into XML +//println stream.toXML(credentials); return ""; //For debug purpose def encoded = [] def sections = credentials.collate(25) for (section in sections) { diff --git a/credentials-migration/update-credentials-folder-level.groovy b/credentials-migration/update-credentials-folder-level.groovy index 2a0ce3e..6df62b2 100644 --- a/credentials-migration/update-credentials-folder-level.groovy +++ b/credentials-migration/update-credentials-folder-level.groovy @@ -14,13 +14,11 @@ import com.thoughtworks.xstream.io.HierarchicalStreamReader import com.thoughtworks.xstream.io.HierarchicalStreamWriter import com.trilead.ssh2.crypto.Base64 import hudson.util.Secret -import hudson.util.XStream2 -import jenkins.model.Jenkins -import com.cloudbees.plugins.credentials.domains.DomainCredentials -import com.trilead.ssh2.crypto.Base64 +import com.cloudbees.plugins.credentials.SecretBytes import hudson.util.XStream2 import jenkins.model.Jenkins import com.cloudbees.plugins.credentials.Credentials +import java.nio.charset.StandardCharsets // Paste the encoded message from the script on the source Jenkins def encoded=[] @@ -34,10 +32,28 @@ if (!encoded) { HashMap> credentialsList; +// This converter ensure that the output XML contains base64 encoded for secretBytes (to handle FileCredentials) +def converterSecretBytes = new Converter() { + @Override + void marshal(Object object, HierarchicalStreamWriter writer, MarshallingContext context) { + writer.value = Base64.encode(new String(object.getPlainData(), StandardCharsets.UTF_8).bytes).toString(); + } + + @Override + Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { + return SecretBytes.fromBytes(new String(Base64.decode(reader.getValue().toCharArray())).getBytes(StandardCharsets.UTF_8)); + } + + @Override + boolean canConvert(Class type) { type == SecretBytes.class } +} + // The message is decoded and unmarshaled for (slice in encoded) { def decoded = new String(Base64.decode(slice.chars)) - domainsFromFolders = new XStream2().fromXML(decoded) as HashMap> ; + def stream = new XStream2() + stream.registerConverter(converterSecretBytes) + domainsFromFolders = stream.fromXML(decoded) as HashMap> ; } def instance = Jenkins.get() @@ -54,7 +70,7 @@ if (!folderExtension.empty) { if (folderDomains!=null) { for (domain in folderDomains) { domainName = domain.getDomain().isGlobal() ? "Global":domain.getDomain().getName() - println " Updating domain " + domainName + println " Updating domain: " + domainName for (credential in domain.credentials) { println " Updating credential: " + credential.id; if (! store.updateCredentials(domain.getDomain(), credential, credential) ){ diff --git a/credentials-migration/update-credentials-system-level.groovy b/credentials-migration/update-credentials-system-level.groovy index b5f576e..0b38e91 100644 --- a/credentials-migration/update-credentials-system-level.groovy +++ b/credentials-migration/update-credentials-system-level.groovy @@ -6,9 +6,16 @@ Description: Decode from export-credentials-root-level.groovy script, all the cr import com.cloudbees.plugins.credentials.SystemCredentialsProvider import com.cloudbees.plugins.credentials.domains.DomainCredentials +import com.thoughtworks.xstream.converters.Converter +import com.thoughtworks.xstream.converters.MarshallingContext +import com.thoughtworks.xstream.converters.UnmarshallingContext +import com.thoughtworks.xstream.io.HierarchicalStreamReader +import com.thoughtworks.xstream.io.HierarchicalStreamWriter import com.trilead.ssh2.crypto.Base64 import hudson.util.XStream2 +import com.cloudbees.plugins.credentials.SecretBytes import jenkins.model.Jenkins +import java.nio.charset.StandardCharsets // Paste the encoded message from the script on the source Jenkins def encoded = [] @@ -19,10 +26,28 @@ if (!encoded) { return } +// This converter ensure that the output XML contains base64 encoded for secretBytes (to handle FileCredentials) +def converterSecretBytes = new Converter() { + @Override + void marshal(Object object, HierarchicalStreamWriter writer, MarshallingContext context) { + writer.value = Base64.encode(new String(object.getPlainData(), StandardCharsets.UTF_8).bytes).toString(); + } + + @Override + Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { + return SecretBytes.fromBytes(new String(Base64.decode(reader.getValue().toCharArray())).getBytes(StandardCharsets.UTF_8)); + } + + @Override + boolean canConvert(Class type) { type == SecretBytes.class } +} + // The message is decoded and unmarshaled for (slice in encoded) { def decoded = new String(Base64.decode(slice.chars)) - def list = new XStream2().fromXML(decoded) as List + def stream = new XStream2() + stream.registerConverter(converterSecretBytes) + def list = stream.fromXML(decoded) as List // Put all the domains from the list into system credentials def store = Jenkins.get().getExtensionList(SystemCredentialsProvider.class).first().getStore() def domainName @@ -30,7 +55,7 @@ for (slice in encoded) { domainName = domain.getDomain().isGlobal() ? "Global":domain.getDomain().getName() println "Updating domain: " + domainName for (credential in domain.credentials) { - println " Updating credential: ${credential.id}" + println " Updating credential: " + credential.id; if (! store.updateCredentials(domain.getDomain(), credential, credential) ){ if (! store.addCredentials(domain.getDomain(), credential) ){ println "ERROR: Unable to add credential ${credential.id}"