Skip to content

Commit

Permalink
enforce Job/read permission in order to read the analysis results for…
Browse files Browse the repository at this point in the history
… a build run and the trend data on the project page

- enforce Job/read permission for JavaScriptMethod in JobAction
- enforce Job/read permission for JavaScriptMethod in ResultAction
  • Loading branch information
sephiroth-j committed Apr 14, 2021
1 parent 2c023bc commit 8857423
Show file tree
Hide file tree
Showing 5 changed files with 202 additions and 0 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# Dependency-Track Jenkins Plugin - Changelog

## Unreleased
### 🐞 Bugs Fixed
- enforce Job/read permission in order to read the analysis results for a build run and the trend data on the project page

## v3.1.1 - 2021-03-30
### 🐞 Bugs Fixed
- [SECURITY-2250](https://issues.jenkins.io/browse/SECURITY-2250). Thanks to Justin Philip for reporting this issue.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ public boolean isTrendVisible() {
*/
@JavaScriptMethod
public JSONArray getSeverityDistributionTrend() {
project.checkPermission(Job.READ);
final List<SeverityDistribution> severityDistributions = project.getBuilds().stream()
.sorted(Comparator.naturalOrder())
.map(run -> run.getAction(ResultAction.class)).filter(Objects::nonNull)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import hudson.Plugin;
import hudson.PluginWrapper;
import hudson.model.Action;
import hudson.model.Job;
import hudson.model.Run;
import java.io.Serializable;
import java.util.Collection;
Expand Down Expand Up @@ -110,6 +111,7 @@ public String getVersionHash() {
*/
@JavaScriptMethod
public JSONArray getFindingsJson() {
run.checkPermission(Job.READ);
return JSONArray.fromObject(findings);
}

Expand Down
108 changes: 108 additions & 0 deletions src/test/java/org/jenkinsci/plugins/DependencyTrack/JobActionTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/*
* Copyright 2021 OWASP.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jenkinsci.plugins.DependencyTrack;

import hudson.model.FreeStyleBuild;
import hudson.model.FreeStyleProject;
import hudson.model.Job;
import hudson.model.Run;
import hudson.model.User;
import hudson.security.ACL;
import hudson.security.ACLContext;
import hudson.util.RunList;
import io.jenkins.plugins.casc.misc.JenkinsConfiguredRule;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import net.sf.json.JSONArray;
import org.acegisecurity.AccessDeniedException;
import org.assertj.core.api.Assertions;
import org.jenkinsci.plugins.DependencyTrack.model.Severity;
import org.jenkinsci.plugins.DependencyTrack.model.SeverityDistribution;
import org.junit.Rule;
import org.junit.Test;
import org.jvnet.hudson.test.MockAuthorizationStrategy;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatCode;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

/**
*
* @author Ronny "Sephiroth" Perinke <sephiroth@sephiroth-j.de>
*/
public class JobActionTest {

@Rule
public JenkinsConfiguredRule j = new JenkinsConfiguredRule();

@Test
public void isTrendVisible() {
Job job = mock(Job.class);
Run run = mock(Run.class);
when(run.getAction(ResultAction.class)).thenReturn(new ResultAction(Collections.emptyList(), new SeverityDistribution(1)));
when(job.getBuilds())
.thenReturn(RunList.fromRuns(Collections.emptyList()))
.thenReturn(RunList.fromRuns(Collections.singletonList(run)));
JobAction uut = new JobAction(job);
assertThat(uut.isTrendVisible()).isFalse();
assertThat(uut.isTrendVisible()).isTrue();
}

@Test
public void getSeverityDistributionTrendPermissionTest() throws IOException {
final MockAuthorizationStrategy mockAuthorizationStrategy = new MockAuthorizationStrategy();
j.jenkins.setAuthorizationStrategy(mockAuthorizationStrategy);
j.jenkins.setSecurityRealm(j.createDummySecurityRealm());
final FreeStyleProject project = j.createFreeStyleProject();
final JobAction uut = new JobAction(project);
final User anonymous = User.getOrCreateByIdOrFullName(ACL.ANONYMOUS_USERNAME);
// without propper permissions
try (ACLContext ignored = ACL.as(anonymous)) {
assertThatThrownBy(() -> uut.getSeverityDistributionTrend()).isInstanceOf(AccessDeniedException.class);
}
// with propper permissions
try (ACLContext ignored = ACL.as(anonymous)) {
mockAuthorizationStrategy.grant(Job.READ).onItems(project).to(anonymous);
assertThatCode(() -> uut.getSeverityDistributionTrend()).doesNotThrowAnyException();
}
}

@Test
public void getSeverityDistribution() throws IOException {
final FreeStyleProject project = j.createFreeStyleProject();
final SeverityDistribution sd1 = new SeverityDistribution(1);
sd1.add(Severity.MEDIUM);
final SeverityDistribution sd2 = new SeverityDistribution(2);
sd2.add(Severity.HIGH);
final ResultAction ra1 = mock(ResultAction.class);
final ResultAction ra2 = mock(ResultAction.class);
when(ra1.getSeverityDistribution()).thenReturn(sd1);
when(ra2.getSeverityDistribution()).thenReturn(sd2);
final FreeStyleBuild b1 = new FreeStyleBuild(project);
b1.addAction(ra1);
final FreeStyleBuild b2 = new FreeStyleBuild(project);
b2.addAction(ra2);
project._getRuns().put(1, b1);
project._getRuns().put(2, b2);

final JobAction uut = new JobAction(project);
Assertions.<JSONArray>assertThat(uut.getSeverityDistributionTrend()).isEqualTo(JSONArray.fromObject(Arrays.asList(sd1, sd2)));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
* Copyright 2021 OWASP.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jenkinsci.plugins.DependencyTrack;

import hudson.model.FreeStyleBuild;
import hudson.model.FreeStyleProject;
import hudson.model.Job;
import hudson.model.User;
import hudson.security.ACL;
import hudson.security.ACLContext;
import io.jenkins.plugins.casc.misc.JenkinsConfiguredRule;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import net.sf.json.JSONArray;
import org.acegisecurity.AccessDeniedException;
import org.assertj.core.api.Assertions;
import org.assertj.core.util.Files;
import org.jenkinsci.plugins.DependencyTrack.model.Finding;
import org.jenkinsci.plugins.DependencyTrack.model.SeverityDistribution;
import org.junit.Rule;
import org.junit.Test;
import org.jvnet.hudson.test.MockAuthorizationStrategy;

import static org.assertj.core.api.Assertions.assertThatCode;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

/**
*
* @author Ronny "Sephiroth" Perinke <sephiroth@sephiroth-j.de>
*/
public class ResultActionTest {

@Rule
public JenkinsConfiguredRule j = new JenkinsConfiguredRule();

private List<Finding> getTestFindings() {
File findings = new File("src/test/resources/findings.json");
return FindingParser.parse(Files.contentOf(findings, StandardCharsets.UTF_8));
}

@Test
public void getFindingsJsonPermissionTest() throws IOException {
final MockAuthorizationStrategy mockAuthorizationStrategy = new MockAuthorizationStrategy();
j.jenkins.setAuthorizationStrategy(mockAuthorizationStrategy);
j.jenkins.setSecurityRealm(j.createDummySecurityRealm());

final FreeStyleProject project = j.createFreeStyleProject();
final FreeStyleBuild b1 = new FreeStyleBuild(project);
final ResultAction uut = new ResultAction(getTestFindings(), new SeverityDistribution(1));
uut.onLoad(b1);

final User anonymous = User.getOrCreateByIdOrFullName(ACL.ANONYMOUS_USERNAME);
// without propper permissions
try (ACLContext ignored = ACL.as(anonymous)) {
assertThatThrownBy(() -> uut.getFindingsJson()).isInstanceOf(AccessDeniedException.class);
}
// with propper permissions
try (ACLContext ignored = ACL.as(anonymous)) {
mockAuthorizationStrategy.grant(Job.READ).onItems(project).to(anonymous);
assertThatCode(() -> uut.getFindingsJson()).doesNotThrowAnyException();
}
}

@Test
public void getFindingsJson() throws IOException {
final FreeStyleProject project = j.createFreeStyleProject();
final FreeStyleBuild b1 = new FreeStyleBuild(project);
final ResultAction uut = new ResultAction(getTestFindings(), new SeverityDistribution(1));
uut.onLoad(b1);
Assertions.<JSONArray>assertThat(uut.getFindingsJson()).isEqualTo(JSONArray.fromObject(getTestFindings()));
}

}

0 comments on commit 8857423

Please sign in to comment.