Skip to content

Commit 34de11f

Browse files
authored
Merge pull request #55 from jenkinsci/SECURITY-1438
[SECURITY-1438] Plaintext password of Gogs is stored in job config.xml
2 parents 2c7fca6 + 8729ada commit 34de11f

File tree

9 files changed

+201
-114
lines changed

9 files changed

+201
-114
lines changed

pom.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,13 @@
101101
<artifactId>jenkins-client</artifactId>
102102
<version>0.3.7</version>
103103
<scope>test</scope>
104+
<exclusions>
105+
<!-- a forked version already included by the core -->
106+
<exclusion>
107+
<groupId>dom4j</groupId>
108+
<artifactId>dom4j</artifactId>
109+
</exclusion>
110+
</exclusions>
104111
</dependency>
105112
<dependency>
106113
<groupId>org.jenkins-ci.plugins</groupId>

src/main/java/org/jenkinsci/plugins/gogs/GogsProjectProperty.java

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ associated documentation files (the "Software"), to deal in the Software without
2727
import hudson.model.Job;
2828
import hudson.model.JobProperty;
2929
import hudson.model.JobPropertyDescriptor;
30+
import hudson.util.Secret;
3031
import net.sf.json.JSONObject;
3132
import org.kohsuke.stapler.DataBoundConstructor;
3233
import org.kohsuke.stapler.StaplerRequest;
@@ -35,18 +36,23 @@ associated documentation files (the "Software"), to deal in the Software without
3536

3637
@SuppressWarnings("ALL")
3738
public class GogsProjectProperty extends JobProperty<Job<?, ?>> {
38-
private final String gogsSecret;
39+
private final Secret gogsSecret;
3940
private final boolean gogsUsePayload;
4041
private final String gogsBranchFilter;
4142

42-
@DataBoundConstructor
43+
@Deprecated
4344
public GogsProjectProperty(String gogsSecret, boolean gogsUsePayload, String gogsBranchFilter) {
45+
this(Secret.fromString(gogsSecret), gogsUsePayload, gogsBranchFilter);
46+
}
47+
48+
@DataBoundConstructor
49+
public GogsProjectProperty(Secret gogsSecret, boolean gogsUsePayload, String gogsBranchFilter) {
4450
this.gogsSecret = gogsSecret;
4551
this.gogsUsePayload = gogsUsePayload;
4652
this.gogsBranchFilter = gogsBranchFilter;
4753
}
4854

49-
public String getGogsSecret() {
55+
public Secret getGogsSecret() {
5056
return this.gogsSecret;
5157
}
5258

@@ -74,12 +80,12 @@ public boolean filterBranch(String ref) {
7480
@Extension
7581
public static final class DescriptorImpl extends JobPropertyDescriptor {
7682
public static final String GOGS_PROJECT_BLOCK_NAME = "gogsProject";
77-
private String gogsSecret;
83+
private Secret gogsSecret;
7884
private boolean gogsUsePayload;
7985
private String gogsBranchFilter;
8086

8187
public String getGogsSecret() {
82-
return gogsSecret;
88+
return Secret.toString(gogsSecret);
8389
}
8490

8591
public boolean getGogsUsePayload() {
@@ -91,13 +97,16 @@ public String getGogsBranchFilter() {
9197
}
9298

9399
public JobProperty<?> newInstance(StaplerRequest req, JSONObject formData) {
94-
GogsProjectProperty tpp = req.bindJSON(
95-
GogsProjectProperty.class,
96-
formData.getJSONObject(GOGS_PROJECT_BLOCK_NAME)
97-
);
100+
GogsProjectProperty tpp = null;
101+
102+
if (req != null) {
103+
tpp = req.bindJSON(
104+
GogsProjectProperty.class,
105+
formData.getJSONObject(GOGS_PROJECT_BLOCK_NAME)
106+
);
107+
}
98108
if (tpp != null) {
99109
LOGGER.finest(formData.toString());
100-
LOGGER.finest(tpp.gogsSecret);
101110
LOGGER.finest(tpp.gogsBranchFilter);
102111

103112
gogsSecret = tpp.gogsSecret;

src/main/java/org/jenkinsci/plugins/gogs/GogsWebHook.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ associated documentation files (the "Software"), to deal in the Software without
2727
import hudson.model.Job;
2828
import hudson.model.UnprotectedRootAction;
2929
import hudson.security.ACL;
30+
import hudson.util.Secret;
3031
import net.sf.json.JSONObject;
3132
import org.acegisecurity.context.SecurityContext;
3233
import org.acegisecurity.context.SecurityContextHolder;
@@ -187,7 +188,7 @@ public void doIndex(StaplerRequest req, StaplerResponse rsp) throws IOException
187188
/* secret is stored in the properties of Job */
188189
final GogsProjectProperty property = (GogsProjectProperty) job.getProperty(GogsProjectProperty.class);
189190
if (property != null) { /* only if Gogs secret is defined on the job */
190-
jSecret = property.getGogsSecret(); /* Secret provided by Jenkins */
191+
jSecret = Secret.toString(property.getGogsSecret()); /* Secret provided by Jenkins */
191192
isRefMatched = property.filterBranch(ref);
192193
}
193194
} else {
@@ -207,7 +208,7 @@ public void doIndex(StaplerRequest req, StaplerResponse rsp) throws IOException
207208
/* secret is stored in the properties of Job */
208209
final GogsProjectProperty property = (GogsProjectProperty) job.getProperty(GogsProjectProperty.class);
209210
if (property != null) { /* only if Gogs secret is defined on the job */
210-
jSecret = property.getGogsSecret(); /* Secret provided by Jenkins */
211+
jSecret = Secret.toString(property.getGogsSecret()); /* Secret provided by Jenkins */
211212
isRefMatched = property.filterBranch(ref);
212213
}
213214
}

src/test/docker/gitserver-dockerfile/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM gogs/gogs:0.11.4
1+
FROM gogs/gogs:0.11.86
22

33
ARG FIRST_USER=dev
44

src/test/docker/gitserver-dockerfile/setup-gogs.sh

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,11 @@ curl -v -X POST -s \
3838
-F "retype=${FIRST_USER}" \
3939
${GITSERVER_URL}/user/sign_up
4040

41-
cat /app/repos-to-mirror
41+
# Create Access token for first user
42+
TOKEN=$(curl -X POST -s -F "name=${FIRST_USER}" -u "${FIRST_USER}:${FIRST_USER}" \
43+
${GITSERVER_URL}/api/v1/users/${FIRST_USER}/tokens | sed 's/.*"sha1":"\(.*\)"}/\1/')
4244

45+
echo $TOKEN
4346
while IFS= read -r LINE || [[ -n "${LINE}" ]];
4447
do
4548
echo "==LINE: ${LINE}"
@@ -50,10 +53,10 @@ do
5053

5154
# Create repo to migrate
5255
curl -v -X POST -s \
56+
-H "Authorization: token ${TOKEN}" \
5357
-F "uid=1" \
5458
-F "clone_addr=${REMOTE_REPO_URL}" \
5559
-F "repo_name=${REPO_NAME}" \
56-
-u "${FIRST_USER}:${FIRST_USER}" \
5760
${GITSERVER_API_URL}/repos/migrate
5861

5962
done < /app/repos-to-mirror

src/test/docker/jenkins-dockerfile/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM jenkinsci/jenkins:latest
1+
FROM jenkins/jenkins:lts-alpine
22

33
# Load the required dependencies for the plugin under test
44
RUN /usr/local/bin/install-plugins.sh git workflow-aggregator pipeline-model-extensions cloudbees-folder

src/test/java/org/jenkinsci/plugins/gogs/GogsConfigHandler.java

Lines changed: 60 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,5 @@
11
package org.jenkinsci.plugins.gogs;
22

3-
import net.sf.json.JSONObject;
4-
import net.sf.json.JSONSerializer;
5-
import org.apache.http.HttpHost;
6-
import org.apache.http.client.fluent.Executor;
7-
import org.apache.http.client.fluent.Form;
8-
import org.apache.http.client.fluent.Request;
9-
import org.apache.http.entity.ContentType;
10-
113
import java.io.File;
124
import java.io.IOException;
135
import java.net.MalformedURLException;
@@ -17,6 +9,15 @@
179
import java.util.concurrent.TimeUnit;
1810
import java.util.concurrent.TimeoutException;
1911

12+
import net.sf.json.JSONArray;
13+
import net.sf.json.JSONObject;
14+
import net.sf.json.JSONSerializer;
15+
import org.apache.http.HttpHost;
16+
import org.apache.http.client.fluent.Executor;
17+
import org.apache.http.client.fluent.Form;
18+
import org.apache.http.client.fluent.Request;
19+
import org.apache.http.entity.ContentType;
20+
2021
/**
2122
* A class to handle the configuration of the Gogs server used during the integration tests.
2223
*/
@@ -28,7 +29,7 @@ public class GogsConfigHandler {
2829
private String gogsServer_password;
2930
private Executor executor = null;
3031
private String gogsServer_apiUrl = null;
31-
32+
private String gogsAccessToken;
3233

3334
/**
3435
* Instantiates an object used to handle operations on a Gogs server.
@@ -46,6 +47,7 @@ public GogsConfigHandler(String gogsUrl, String user, String password) throws Ma
4647
this.gogsServer_port = aURL.getPort();
4748
this.gogsServer_user = user;
4849
this.gogsServer_password = password;
50+
this.gogsAccessToken = getGogsAccessToken();
4951
}
5052

5153
/**
@@ -60,10 +62,10 @@ void waitForServer(int retries, int retryDelay) throws TimeoutException, Interru
6062
String testUrl = this.getGogsUrl() + "/";
6163

6264
for (int i = 0; i < retries; i++) {
63-
int status = 0;
65+
int status;
6466
try {
6567
status = Request.Get(testUrl)
66-
.execute().returnResponse().getStatusLine().getStatusCode();
68+
.execute().returnResponse().getStatusLine().getStatusCode();
6769
} catch (IOException e) {
6870
TimeUnit.SECONDS.sleep(retryDelay);
6971
continue;
@@ -100,14 +102,17 @@ int createWebHook(String jsonCommand, String projectName) throws IOException {
100102
+ "/" + projectName + "/hooks";
101103

102104
Executor executor = getExecutor();
105+
Request request = Request.Post(gogsHooksConfigUrl);
106+
107+
if (gogsAccessToken != null) {
108+
request.addHeader("Authorization", "token " + gogsAccessToken);
109+
}
103110

104111
String result = executor
105-
.execute(Request.Post(gogsHooksConfigUrl).bodyString(jsonCommand, ContentType.APPLICATION_JSON))
112+
.execute(request.bodyString(jsonCommand, ContentType.APPLICATION_JSON))
106113
.returnContent().asString();
107114
JSONObject jsonObject = (JSONObject) JSONSerializer.toJSON( result );
108-
int id = jsonObject.getInt("id");
109-
110-
return id;
115+
return jsonObject.getInt("id");
111116
}
112117

113118
/**
@@ -138,9 +143,14 @@ void removeHook(String projectName, int hookId) throws IOException {
138143
+ "/" + projectName + "/hooks/" + hookId;
139144

140145
Executor executor = getExecutor();
146+
Request request = Request.Delete(gogsHooksConfigUrl);
147+
148+
if (gogsAccessToken != null) {
149+
request.addHeader("Authorization", "token " + gogsAccessToken);
150+
}
141151

142152
int result = executor
143-
.execute(Request.Delete(gogsHooksConfigUrl))
153+
.execute(request)
144154
.returnResponse().getStatusLine().getStatusCode();
145155

146156
if (result != 204) {
@@ -159,16 +169,20 @@ void createEmptyRepo(String projectName) throws IOException {
159169

160170
Executor executor = getExecutor();
161171
String gogsHooksConfigUrl = getGogsServer_apiUrl() + "user/repos";
172+
Request request = Request.Post(gogsHooksConfigUrl);
173+
174+
if (this.gogsAccessToken != null) {
175+
request.addHeader("Authorization", "token " + this.gogsAccessToken);
176+
}
162177

163178
int result = executor
164-
.execute(Request
165-
.Post(gogsHooksConfigUrl)
179+
.execute(request
166180
.bodyForm(Form.form()
167-
.add("name", projectName)
168-
.add("description", "API generated repository")
169-
.add("private", "true")
170-
.add("auto_init", "false")
171-
.build()
181+
.add("name", projectName)
182+
.add("description", "API generated repository")
183+
.add("private", "true")
184+
.add("auto_init", "false")
185+
.build()
172186
)
173187
)
174188
.returnResponse().getStatusLine().getStatusCode();
@@ -190,49 +204,37 @@ private Executor getExecutor() {
190204
if (this.executor == null) {
191205
HttpHost httpHost = new HttpHost(this.gogsServer_nodeName, this.gogsServer_port);
192206
this.executor = Executor.newInstance()
193-
.auth(httpHost, this.gogsServer_user, this.gogsServer_password)
194-
.authPreemptive(httpHost);
207+
.auth(httpHost, this.gogsServer_user, this.gogsServer_password)
208+
.authPreemptive(httpHost);
195209
}
196210
return this.executor;
197211
}
198212

213+
/**
214+
* Get Access token of the user.
215+
*
216+
* @return an access token of the user
217+
*/
218+
public String getGogsAccessToken() {
219+
String resp;
220+
String sha1 = null;
221+
Executor executor = getExecutor();
222+
try {
223+
resp = executor.execute(
224+
Request.Get(this.getGogsUrl() + "/api/v1/users/" + this.gogsServer_user + "/tokens")
225+
).returnContent().toString();
226+
JSONArray jsonArray = JSONArray.fromObject(resp);
227+
if (!jsonArray.isEmpty()) {
228+
sha1 = ((JSONObject) jsonArray.get(0)).getString("sha1");
229+
}
230+
} catch (IOException e) { }
231+
return sha1;
232+
}
233+
199234
public String getGogsServer_apiUrl() {
200235
if (this.gogsServer_apiUrl == null) {
201236
this.gogsServer_apiUrl = this.getGogsUrl() + "/api/v1/";
202237
}
203238
return gogsServer_apiUrl;
204239
}
205-
206-
public String getGogsServer_nodeName() {
207-
return gogsServer_nodeName;
208-
}
209-
210-
public void setGogsServer_nodeName(String gogsServer_nodeName) {
211-
this.gogsServer_nodeName = gogsServer_nodeName;
212-
}
213-
214-
public int getGogsServer_port() {
215-
return gogsServer_port;
216-
}
217-
218-
public void setGogsServer_port(int gogsServer_port) {
219-
this.gogsServer_port = gogsServer_port;
220-
}
221-
222-
public String getGogsServer_user() {
223-
return gogsServer_user;
224-
}
225-
226-
public void setGogsServer_user(String gogsServer_user) {
227-
this.gogsServer_user = gogsServer_user;
228-
}
229-
230-
public String getGogsServer_password() {
231-
return gogsServer_password;
232-
}
233-
234-
public void setGogsServer_password(String gogsServer_password) {
235-
this.gogsServer_password = gogsServer_password;
236-
}
237-
238240
}

0 commit comments

Comments
 (0)