Skip to content

Commit 7968e3f

Browse files
SerosMarkEWaite
andauthored
Escape special characters for GitUsernamePasswordBinding in withCrede… (#1443)
* Escape special characters for GitUsernamePasswordBinding in withCredentials * Fix test for GitUsernamePasswordBinding in withCredentials * Adapt writing ASKPASS from git-client-plugin * Fix tests * Reduce diffs by retaining old, ugly formatting of comment In the future, the repository will be formatted with spotless and that ugliness will be banished forever. Helps my code review to make the diffs small now. * Make filename encoding methods private No need to make them visible outside the class where they are used. Also adds the same comment on these methods as is used on the methods in the git client plugin so that future consumers will know to not use them for any other purpose than their current very limited use. * Add more sample passwords * Move assertions into existing conditional --------- Co-authored-by: Mark Waite <mark.earl.waite@gmail.com>
1 parent c75dea6 commit 7968e3f

File tree

2 files changed

+42
-12
lines changed

2 files changed

+42
-12
lines changed

src/main/java/jenkins/plugins/git/GitUsernamePasswordBinding.java

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -145,23 +145,28 @@ protected GenerateGitScript(String gitUsername, String gitPassword,
145145
protected FilePath write(StandardUsernamePasswordCredentials credentials, FilePath workspace)
146146
throws IOException, InterruptedException {
147147
FilePath gitEcho;
148+
149+
FilePath usernameFile = workspace.createTempFile("username", ".txt");
150+
usernameFile.write(this.userVariable + "\n", null);
151+
FilePath passwordFile = workspace.createTempFile("password", ".txt");
152+
passwordFile.write(this.passVariable + "\n", null);
153+
148154
//Hard Coded platform dependent newLine
149155
if (this.unixNodeType) {
150156
gitEcho = workspace.createTempFile("auth", ".sh");
151-
// [#!/usr/bin/env sh] to be used if required, could have some corner cases
152-
gitEcho.write("case $1 in\n"
153-
+ " Username*) echo " + this.userVariable
154-
+ " ;;\n"
155-
+ " Password*) echo " + this.passVariable
156-
+ " ;;\n"
157+
gitEcho.write("#!/bin/sh\n"
158+
+ "\n"
159+
+ "case \"$1\" in\n"
160+
+ " Username*) cat " + unixArgEncodeFileName(usernameFile.getRemote()) + ";;\n"
161+
+ " Password*) cat " + unixArgEncodeFileName(passwordFile.getRemote()) + ";;\n"
157162
+ " esac\n", null);
158163
gitEcho.chmod(0500);
159164
} else {
160165
gitEcho = workspace.createTempFile("auth", ".bat");
161166
gitEcho.write("@ECHO OFF\r\n"
162167
+ "SET ARG=%~1\r\n"
163-
+ "IF %ARG:~0,8%==Username (ECHO " + this.userVariable + ")\r\n"
164-
+ "IF %ARG:~0,8%==Password (ECHO " + this.passVariable + ")", null);
168+
+ "IF %ARG:~0,8%==Username type " + windowsArgEncodeFileName(usernameFile.getRemote()) + "\r\n"
169+
+ "IF %ARG:~0,8%==Password type " + windowsArgEncodeFileName(passwordFile.getRemote()), null);
165170
}
166171
return gitEcho;
167172
}
@@ -170,6 +175,26 @@ protected FilePath write(StandardUsernamePasswordCredentials credentials, FilePa
170175
protected Class<StandardUsernamePasswordCredentials> type() {
171176
return StandardUsernamePasswordCredentials.class;
172177
}
178+
179+
/* Escape all single quotes in filename, then surround filename in single quotes.
180+
* Only useful to prepare filename for reference from a shell script.
181+
*/
182+
private String unixArgEncodeFileName(String filename) {
183+
if (filename.contains("'")) {
184+
filename = filename.replace("'", "'\\''");
185+
}
186+
return "'" + filename + "'";
187+
}
188+
189+
/* Escape all double quotes in filename, then surround filename in double quotes.
190+
* Only useful to prepare filename for reference from a DOS batch file.
191+
*/
192+
private String windowsArgEncodeFileName(String filename) {
193+
if (filename.contains("\"")) {
194+
filename = filename.replace("\"", "^\"");
195+
}
196+
return "\"" + filename + "\"";
197+
}
173198
}
174199

175200
// Mistakenly defined GitUsernamePassword in first release, prefer gitUsernamePassword as symbol

src/test/java/jenkins/plugins/git/GitUsernamePasswordBindingTest.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,10 @@ private boolean isTimeAvailable() {
116116
"&Ampersand&",
117117
"He said \"Hello\", then left.",
118118
"default=@#(*^!",
119+
"has_a_trailing_quote=@#(*^!'",
119120
"here's-a-quote",
120121
"special%%_342@**",
122+
"%interior-single-quote%_786'@**",
121123
};
122124
private static GitTool[] gitTools = {
123125
new GitTool("Default", "git", null),
@@ -126,10 +128,11 @@ private boolean isTimeAvailable() {
126128
new JGitTool(),
127129
};
128130

129-
/* Create two test data items using random selections from the larger set of data */
131+
/* Create three test data items using random selections from the larger set of data */
130132
private static Object[][] testData = new Object[][]{
131133
{userNames[random.nextInt(userNames.length)], passwords[random.nextInt(passwords.length)], gitTools[random.nextInt(gitTools.length)]},
132134
{userNames[random.nextInt(userNames.length)], passwords[random.nextInt(passwords.length)], gitTools[random.nextInt(gitTools.length)]},
135+
{userNames[random.nextInt(userNames.length)], passwords[random.nextInt(passwords.length)], gitTools[random.nextInt(gitTools.length)]},
133136
};
134137

135138
public GitUsernamePasswordBindingTest(String username, String password, GitTool gitToolInstance) {
@@ -309,19 +312,21 @@ public void test_getGitClientInstance() throws IOException, InterruptedException
309312
}
310313

311314
@Test
312-
public void test_GenerateGitScript_write() throws IOException, InterruptedException {
315+
public void test_GenerateGitScript_write() throws Exception {
313316
assumeTrue("Test class max time " + MAX_SECONDS_FOR_THESE_TESTS + " exceeded", isTimeAvailable());
314317
GitUsernamePasswordBinding.GenerateGitScript tempGenScript = new GitUsernamePasswordBinding.GenerateGitScript(this.username, this.password, credentials.getId(), !isWindows());
315318
assertThat(tempGenScript.type(), is(StandardUsernamePasswordCredentials.class));
316319
FilePath tempScriptFile = tempGenScript.write(credentials, rootFilePath);
317320
if (!isWindows()) {
318321
assertThat(tempScriptFile.mode(), is(0500));
319322
assertThat("File extension not sh", FilenameUtils.getExtension(tempScriptFile.getName()), is("sh"));
323+
assertThat(tempScriptFile.readToString(), containsString("Username*) cat"));
324+
assertThat(tempScriptFile.readToString(), containsString("Password*) cat"));
320325
} else {
321326
assertThat("File extension not bat", FilenameUtils.getExtension(tempScriptFile.getName()), is("bat"));
327+
assertThat(tempScriptFile.readToString(), containsString("IF %ARG:~0,8%==Username type"));
328+
assertThat(tempScriptFile.readToString(), containsString("IF %ARG:~0,8%==Password type"));
322329
}
323-
assertThat(tempScriptFile.readToString(), containsString(this.username));
324-
assertThat(tempScriptFile.readToString(), containsString(this.password));
325330
}
326331

327332
/**

0 commit comments

Comments
 (0)