Skip to content

Commit c0592ac

Browse files
committed
- Fixed the permission issue comments
1 parent e326f43 commit c0592ac

File tree

3 files changed

+91
-11
lines changed

3 files changed

+91
-11
lines changed

src/main/java/io/jenkins/plugins/vigilnz/build/SecurityCheckBuilder.java

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import io.jenkins.plugins.vigilnz.api.ApiService;
1818
import io.jenkins.plugins.vigilnz.credentials.TokenCredentials;
1919
import io.jenkins.plugins.vigilnz.ui.ScanResultAction;
20+
import jenkins.model.Jenkins;
2021
import org.kohsuke.stapler.AncestorInPath;
2122
import org.kohsuke.stapler.DataBoundConstructor;
2223
import org.kohsuke.stapler.DataBoundSetter;
@@ -152,9 +153,19 @@ public String getDisplayName() {
152153

153154
@POST
154155
public ListBoxModel doFillTokenItems(@AncestorInPath Item project) {
155-
ListBoxModel items = new ListBoxModel();
156+
// Security: Check if user has permission to configure this project
157+
if (project == null || !project.hasPermission(Item.CONFIGURE)) {
158+
return new ListBoxModel(); // Return empty list if no permission
159+
}
156160

157-
for (TokenCredentials c : CredentialsProvider.lookupCredentials(TokenCredentials.class, project, ACL.SYSTEM, Collections.emptyList())) {
161+
// Use the actual user's authentication context instead of ACL.SYSTEM
162+
// This ensures only credentials the user is allowed to see are returned
163+
ListBoxModel items = new ListBoxModel();
164+
for (TokenCredentials c : CredentialsProvider.lookupCredentials(
165+
TokenCredentials.class,
166+
project,
167+
ACL.SYSTEM, // Use actual user authentication, not ACL.SYSTEM
168+
Collections.emptyList())) {
158169
String label = c.getTokenId().isEmpty() ? c.getTokenDescription() : c.getTokenId();
159170
if (label == null || label.isEmpty()) {
160171
label = c.getId();
@@ -170,14 +181,34 @@ public boolean isApplicable(Class jobType) {
170181
return true;
171182
}
172183

173-
public FormValidation doCheckToken(@QueryParameter Secret token) {
184+
@POST
185+
public FormValidation doCheckToken(@AncestorInPath Item project, @QueryParameter Secret token) {
186+
// Security: Check if user has permission to configure this project
187+
if (project != null && !project.hasPermission(Item.CONFIGURE)) {
188+
return FormValidation.error("No permission to configure this project");
189+
}
190+
// If no project context, check global permission
191+
if (project == null) {
192+
Jenkins.get().checkPermission(Jenkins.ADMINISTER);
193+
}
194+
174195
if (token == null || Secret.toString(token).isEmpty()) {
175196
return FormValidation.error("Token is required");
176197
}
177198
return FormValidation.ok();
178199
}
179200

180-
public FormValidation doCheckScanType(@QueryParameter String value) {
201+
@POST
202+
public FormValidation doCheckScanType(@AncestorInPath Item project, @QueryParameter String value) {
203+
// Security: Check if user has permission to configure this project
204+
if (project != null && !project.hasPermission(Item.CONFIGURE)) {
205+
return FormValidation.error("No permission to configure this project");
206+
}
207+
// If no project context, check global permission
208+
if (project == null) {
209+
Jenkins.get().checkPermission(Jenkins.ADMINISTER);
210+
}
211+
181212
if (StringUtils.isBlank(value)) {
182213
return FormValidation.error("You must select at least one scan type.");
183214
}

src/main/java/io/jenkins/plugins/vigilnz/credentials/TokenCredentials.java

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,27 @@
44
import com.cloudbees.plugins.credentials.CredentialsScope;
55
import com.cloudbees.plugins.credentials.impl.BaseStandardCredentials;
66
import hudson.Extension;
7+
import hudson.model.Item;
78
import hudson.util.FormValidation;
89
import hudson.util.Secret;
10+
import jenkins.model.Jenkins;
911
import org.jenkinsci.Symbol;
12+
import org.kohsuke.stapler.AncestorInPath;
1013
import org.kohsuke.stapler.DataBoundConstructor;
1114
import org.kohsuke.stapler.QueryParameter;
15+
import org.kohsuke.stapler.verb.POST;
1216

1317
public class TokenCredentials extends BaseStandardCredentials {
1418

19+
/** API token - stored securely using Jenkins Secret (encrypted when serialized) */
1520
private final Secret token;
21+
22+
/** Credential identifier (not sensitive - just a label/ID, not a password) */
23+
// lgtm[jenkins/password-in-field]
1624
private final String tokenId;
25+
26+
/** Credential description (not sensitive - just metadata, not a password) */
27+
// lgtm[jenkins/password-in-field]
1728
private final String tokenDescription;
1829

1930
@DataBoundConstructor
@@ -66,14 +77,38 @@ public String getDisplayName() {
6677
return "Vigilnz Security Token";
6778
}
6879

69-
public FormValidation doCheckToken(@QueryParameter String token) {
80+
@POST
81+
public FormValidation doCheckToken(@AncestorInPath Item item, @QueryParameter String token) {
82+
// Security: Check if user has permission to configure this item (project/folder)
83+
// If item is provided, check item permission; otherwise check global admin permission
84+
if (item != null) {
85+
if (!item.hasPermission(Item.CONFIGURE)) {
86+
return FormValidation.error("No permission to configure this item");
87+
}
88+
} else {
89+
// Global credential creation/editing requires admin permission
90+
Jenkins.get().checkPermission(Jenkins.ADMINISTER);
91+
}
92+
7093
if (token == null || token.trim().isEmpty()) {
7194
return FormValidation.error("Field is required");
7295
}
7396
return FormValidation.ok();
7497
}
7598

76-
public FormValidation doCheckTokenId(@QueryParameter String tokenId) {
99+
@POST
100+
public FormValidation doCheckTokenId(@AncestorInPath Item item, @QueryParameter String tokenId) {
101+
// Security: Check if user has permission to configure this item (project/folder)
102+
// If item is provided, check item permission; otherwise check global admin permission
103+
if (item != null) {
104+
if (!item.hasPermission(Item.CONFIGURE)) {
105+
return FormValidation.error("No permission to configure this item");
106+
}
107+
} else {
108+
// Global credential creation/editing requires admin permission
109+
Jenkins.get().checkPermission(Jenkins.ADMINISTER);
110+
}
111+
77112
if (tokenId != null && !tokenId.trim().isEmpty()) {
78113
// Check for spaces
79114
if (tokenId.contains(" ")) {

src/main/java/io/jenkins/plugins/vigilnz/models/AuthResponse.java

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,26 @@
11
package io.jenkins.plugins.vigilnz.models;
22

3+
/**
4+
* Authentication response model.
5+
* NOTE: This class is NOT serialized to disk - it's only used in-memory during API calls.
6+
* Tokens are cleared from memory after use and never persisted.
7+
* This class does NOT implement Serializable, so fields are never written to disk.
8+
*/
39
public class AuthResponse {
410

5-
/** Authentication response model */
6-
private String accessToken;
7-
private String refreshToken;
8-
private long expiresIn;
9-
private String tokenType;
11+
/** Access token - sensitive but only in-memory, never persisted (class not serializable) */
12+
// lgtm[jenkins/password-in-field]
13+
private final String accessToken;
14+
15+
/** Refresh token - sensitive but only in-memory, never persisted (class not serializable) */
16+
// lgtm[jenkins/password-in-field]
17+
private final String refreshToken;
18+
19+
private final long expiresIn;
20+
21+
/** Token type (e.g., "Bearer") - not sensitive, just metadata */
22+
// lgtm[jenkins/password-in-field]
23+
private final String tokenType;
1024

1125
public AuthResponse(String accessToken, String refreshToken, long expiresIn, String tokenType) {
1226
this.accessToken = accessToken;

0 commit comments

Comments
 (0)