Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[JENKINS-36432 followup] Add tests of migration and reading plain-text
- The reading of plain-text from the on-disk XML is for e.g. people using chef/puppet scripts to pre-populate their JENKINS_HOME - The reading of plain-text from the CLI create credentials command is an obvious additional use case. This also applies to the REST API for credentials creation, but as the REST API is already tested in the credentials plugin I do not see any value in adding a specific test for that scenario. - The migration of legacy data intact is also an obvious requirement
- Loading branch information
Showing
10 changed files
with
237 additions
and
1 deletion.
There are no files selected for viewing
2 changes: 1 addition & 1 deletion
2
src/main/java/org/jenkinsci/plugins/plaincredentials/impl/FileCredentialsImpl.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
190 changes: 190 additions & 0 deletions
190
src/test/java/org/jenkinsci/plugins/plaincredentials/SecretBytesTest.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,190 @@ | ||
/* | ||
* The MIT License | ||
* | ||
* Copyright 2016 Stephen Connolly and 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 org.jenkinsci.plugins.plaincredentials; | ||
|
||
import com.cloudbees.plugins.credentials.CredentialsMatchers; | ||
import com.cloudbees.plugins.credentials.CredentialsProvider; | ||
import com.cloudbees.plugins.credentials.SecretBytes; | ||
import com.cloudbees.plugins.credentials.SystemCredentialsProvider; | ||
import com.cloudbees.plugins.credentials.cli.CreateCredentialsByXmlCommand; | ||
import com.cloudbees.plugins.credentials.domains.DomainRequirement; | ||
import hudson.cli.CLICommandInvoker; | ||
import hudson.security.ACL; | ||
import java.io.ByteArrayInputStream; | ||
import java.io.File; | ||
import java.nio.charset.Charset; | ||
import java.util.List; | ||
import org.apache.commons.codec.binary.Base64; | ||
import org.apache.commons.io.FileUtils; | ||
import org.apache.commons.io.IOUtils; | ||
import org.jenkinsci.plugins.plaincredentials.impl.FileCredentialsImpl; | ||
import org.junit.Rule; | ||
import org.junit.Test; | ||
import org.jvnet.hudson.test.JenkinsRule; | ||
import org.jvnet.hudson.test.recipes.LocalData; | ||
|
||
import static hudson.cli.CLICommandInvoker.Matcher.succeededSilently; | ||
import static org.hamcrest.Matchers.*; | ||
import static org.junit.Assert.*; | ||
import static org.junit.Assume.*; | ||
|
||
public class SecretBytesTest { | ||
|
||
@Rule | ||
public JenkinsRule r = new JenkinsRule(); | ||
|
||
/** | ||
* Verifies that {@link SecretBytes} will treat a Base64 encoded plain text content as the content to be encrypted | ||
* with the instance's secret key which gets applied when the {@link FileCredentialsImpl} is written to disk. | ||
* @throws Exception if things go wrong. | ||
*/ | ||
@Test | ||
@LocalData | ||
public void loadUnencrypted() throws Exception { | ||
// these are the magic strings | ||
assumeThat(Base64.encodeBase64("This is Base64 encoded plain text\n".getBytes("UTF-8")), is( | ||
"VGhpcyBpcyBCYXNlNjQgZW5jb2RlZCBwbGFpbiB0ZXh0Cg==".getBytes("US-ASCII"))); | ||
|
||
// first check that the file on disk contains the unencrypted text | ||
assertThat(FileUtils.readFileToString(new File(r.jenkins.getRootDir(), "credentials.xml")), | ||
containsString("VGhpcyBpcyBCYXNlNjQgZW5jb2RlZCBwbGFpbiB0ZXh0Cg==")); | ||
|
||
// get the credential instance under test | ||
FileCredentials c = CredentialsMatchers.firstOrNull( | ||
CredentialsProvider.lookupCredentials( | ||
FileCredentials.class, | ||
r.jenkins, | ||
ACL.SYSTEM, | ||
(List<DomainRequirement>) null | ||
), | ||
CredentialsMatchers.withId("secret-file") | ||
); | ||
|
||
// we have the credential instance we think we should have | ||
assertThat(c, notNullValue()); | ||
assertThat(c.getFileName(), is("secret.txt")); | ||
assertThat(c.getDescription(), is("a line")); | ||
|
||
// now check that the content has been read correctly | ||
assertThat(IOUtils.toString(c.getContent(), "UTF-8"), is("This is Base64 encoded plain text\n")); | ||
|
||
// now when we re-save the credentials this should encrypt with the instance's secret key | ||
SystemCredentialsProvider.getInstance().save(); | ||
assertThat(FileUtils.readFileToString(new File(r.jenkins.getRootDir(), "credentials.xml")), | ||
not(containsString("VGhpcyBpcyBCYXNlNjQgZW5jb2RlZCBwbGFpbiB0ZXh0Cg=="))); | ||
} | ||
|
||
/** | ||
* Verifies that {@link SecretBytes} will treat a Base64 encoded plain text content as the content to be encrypted | ||
* with the instance's secret key which gets applied when the {@link FileCredentialsImpl} is written to disk. | ||
* @throws Exception if things go wrong. | ||
*/ | ||
@Test | ||
@LocalData | ||
public void migrateLegacyData() throws Exception { | ||
// first check that the file on disk contains the legacy format | ||
assertThat(FileUtils.readFileToString(new File(r.jenkins.getRootDir(), "credentials.xml")), | ||
allOf(containsString("</data>"), not(containsString("</secretBytes>")))); | ||
|
||
// get the credential instance under test | ||
FileCredentials c = CredentialsMatchers.firstOrNull( | ||
CredentialsProvider.lookupCredentials( | ||
FileCredentials.class, | ||
r.jenkins, | ||
ACL.SYSTEM, | ||
(List<DomainRequirement>) null | ||
), | ||
CredentialsMatchers.withId("legacyData") | ||
); | ||
|
||
// we have the credential instance we think we should have | ||
assertThat(c, notNullValue()); | ||
assertThat(c.getFileName(), is("secret.txt")); | ||
assertThat(c.getDescription(), is("credential using legacy data format")); | ||
|
||
// now check that the content has been converted | ||
assertThat(IOUtils.toString(c.getContent(), "UTF-8"), is("This is a secret file from legacy encryption\n")); | ||
|
||
// now when we re-save the credentials this should persist in the new format | ||
SystemCredentialsProvider.getInstance().save(); | ||
assertThat(FileUtils.readFileToString(new File(r.jenkins.getRootDir(), "credentials.xml")), | ||
allOf(not(containsString("</data>")), containsString("</secretBytes>"))); | ||
} | ||
|
||
@Test | ||
public void createFileCredentialsByXml() throws Exception { | ||
// get the credential instance doesn't exist yet | ||
FileCredentials c = CredentialsMatchers.firstOrNull( | ||
CredentialsProvider.lookupCredentials( | ||
FileCredentials.class, | ||
r.jenkins, | ||
ACL.SYSTEM, | ||
(List<DomainRequirement>) null | ||
), | ||
CredentialsMatchers.withId("secret-file") | ||
); | ||
assertThat(c, nullValue()); | ||
|
||
// create the credentials | ||
CreateCredentialsByXmlCommand cmd = new CreateCredentialsByXmlCommand(); | ||
CLICommandInvoker invoker = new CLICommandInvoker(r, cmd); | ||
assertThat(invoker.withStdin(new ByteArrayInputStream(("<?xml version='1.0' encoding='UTF-8'?>\n" | ||
+ "<org.jenkinsci.plugins.plaincredentials.impl.FileCredentialsImpl>\n" | ||
+ " <scope>GLOBAL</scope>\n" | ||
+ " <id>secret-file</id>\n" | ||
+ " <description>a line</description>\n" | ||
+ " <fileName>secret.txt</fileName>\n" | ||
+ " <secretBytes>VGhpcyBpcyBCYXNlNjQgZW5jb2RlZCBwbGFpbiB0ZXh0Cg==</secretBytes>\n" | ||
+ "</org.jenkinsci.plugins.plaincredentials.impl.FileCredentialsImpl>\n") | ||
.getBytes(Charset.forName("UTF-8")))) | ||
.invokeWithArgs("system::system::jenkins", "_"), | ||
succeededSilently()); | ||
|
||
// get the credential instance under test | ||
c = CredentialsMatchers.firstOrNull( | ||
CredentialsProvider.lookupCredentials( | ||
FileCredentials.class, | ||
r.jenkins, | ||
ACL.SYSTEM, | ||
(List<DomainRequirement>) null | ||
), | ||
CredentialsMatchers.withId("secret-file") | ||
); | ||
|
||
// we have the credential instance we think we should have | ||
assertThat(c, notNullValue()); | ||
assertThat(c.getFileName(), is("secret.txt")); | ||
assertThat(c.getDescription(), is("a line")); | ||
|
||
// now check that the content has been read correctly | ||
assertThat(IOUtils.toString(c.getContent(), "UTF-8"), is("This is Base64 encoded plain text\n")); | ||
|
||
// now when we re-save the credentials this should encrypt with the instance's secret key | ||
SystemCredentialsProvider.getInstance().save(); | ||
assertThat(FileUtils.readFileToString(new File(r.jenkins.getRootDir(), "credentials.xml")), | ||
not(containsString("VGhpcyBpcyBCYXNlNjQgZW5jb2RlZCBwbGFpbiB0ZXh0Cg=="))); | ||
} | ||
|
||
} |
2 changes: 2 additions & 0 deletions
2
...sources/org/jenkinsci/plugins/plaincredentials/SecretBytesTest/loadUnencrypted/config.xml
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,2 @@ | ||
<?xml version='1.0' encoding='UTF-8'?> | ||
<hudson/> |
19 changes: 19 additions & 0 deletions
19
...es/org/jenkinsci/plugins/plaincredentials/SecretBytesTest/loadUnencrypted/credentials.xml
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,19 @@ | ||
<?xml version='1.0' encoding='UTF-8'?> | ||
<com.cloudbees.plugins.credentials.SystemCredentialsProvider plugin="credentials@2.1.5"> | ||
<domainCredentialsMap class="hudson.util.CopyOnWriteMap$Hash"> | ||
<entry> | ||
<com.cloudbees.plugins.credentials.domains.Domain> | ||
<specifications/> | ||
</com.cloudbees.plugins.credentials.domains.Domain> | ||
<java.util.concurrent.CopyOnWriteArrayList> | ||
<org.jenkinsci.plugins.plaincredentials.impl.FileCredentialsImpl plugin="plain-credentials@1.3-SNAPSHOT"> | ||
<scope>GLOBAL</scope> | ||
<id>secret-file</id> | ||
<description>a line</description> | ||
<fileName>secret.txt</fileName> | ||
<secretBytes>VGhpcyBpcyBCYXNlNjQgZW5jb2RlZCBwbGFpbiB0ZXh0Cg==</secretBytes> | ||
</org.jenkinsci.plugins.plaincredentials.impl.FileCredentialsImpl> | ||
</java.util.concurrent.CopyOnWriteArrayList> | ||
</entry> | ||
</domainCredentialsMap> | ||
</com.cloudbees.plugins.credentials.SystemCredentialsProvider> |
2 changes: 2 additions & 0 deletions
2
...urces/org/jenkinsci/plugins/plaincredentials/SecretBytesTest/migrateLegacyData/config.xml
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,2 @@ | ||
<?xml version='1.0' encoding='UTF-8'?> | ||
<hudson/> |
19 changes: 19 additions & 0 deletions
19
.../org/jenkinsci/plugins/plaincredentials/SecretBytesTest/migrateLegacyData/credentials.xml
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,19 @@ | ||
<?xml version='1.0' encoding='UTF-8'?> | ||
<com.cloudbees.plugins.credentials.SystemCredentialsProvider plugin="credentials@2.1.5"> | ||
<domainCredentialsMap class="hudson.util.CopyOnWriteMap$Hash"> | ||
<entry> | ||
<com.cloudbees.plugins.credentials.domains.Domain> | ||
<specifications/> | ||
</com.cloudbees.plugins.credentials.domains.Domain> | ||
<java.util.concurrent.CopyOnWriteArrayList> | ||
<org.jenkinsci.plugins.plaincredentials.impl.FileCredentialsImpl plugin="plain-credentials@1.2"> | ||
<scope>GLOBAL</scope> | ||
<id>legacyData</id> | ||
<description>credential using legacy data format</description> | ||
<fileName>secret.txt</fileName> | ||
<data>DMG4Q+h/SWXBvMJQy7vMACNZgmCVggCvjP5qeNqsAQo8o7dC69vHlHOjReE1MDIr</data> | ||
</org.jenkinsci.plugins.plaincredentials.impl.FileCredentialsImpl> | ||
</java.util.concurrent.CopyOnWriteArrayList> | ||
</entry> | ||
</domainCredentialsMap> | ||
</com.cloudbees.plugins.credentials.SystemCredentialsProvider> |
1 change: 1 addition & 0 deletions
1
...urces/org/jenkinsci/plugins/plaincredentials/SecretBytesTest/migrateLegacyData/secret.key
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 @@ | ||
479791e961495d820f337e3afd8fcb70aa36d8c4738093de71d13f7fe6ed6fa0 |
1 change: 1 addition & 0 deletions
1
...g/jenkinsci/plugins/plaincredentials/SecretBytesTest/migrateLegacyData/secrets/master.key
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 @@ | ||
85f522c34c8efc07970009211478cd1e0aa2c85e75bae2b5ff4396d38d6a97dd03717f48447313597c3e3c8ede2e7fb131c3e383366dea755f39af06d0fcf9c2ac6b9fbadca31180f8346372c5e78d4b9bc790393de47f36170a0d30da7aa022c3ccb8ccf7a073dc1a220877fe5554d0b8558800a9ea43ea38a87a54c52ebfc9 |
Binary file added
BIN
+272 Bytes
...grateLegacyData/secrets/org.jenkinsci.main.modules.instance_identity.InstanceIdentity.KEY
Binary file not shown.
2 changes: 2 additions & 0 deletions
2
...migrateLegacyData/secrets/org.jenkinsci.plugins.plaincredentials.impl.FileCredentialsImpl
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,2 @@ | ||
�F�)�,$�x{����Ԗ�~�$���p�/�������a��n$���-Ʉ��&���=�T�X/��+��egܨ^� | ||
��_u�5�oT?�����v)j$9�ZέX,v�4 �=ul-���yV]���^�� �%J��cT8x;dU,-��.�tK].� ��K���n�_��}_f���o��q�Sn_2"S����҉f^6n������h�-��zVዿ�����ٿsz;h�%dz-CpЃ�m_&����9�>� |