Skip to content

Commit 6ed2ddd

Browse files
authored
Merge pull request #5996 from nscuro/backport-pr-5994
Backport: Support Sonatype Guide tokens for OSS Index analyzer
2 parents 59784ef + 106abe4 commit 6ed2ddd

File tree

2 files changed

+68
-18
lines changed

2 files changed

+68
-18
lines changed

src/main/java/org/dependencytrack/tasks/scanners/OssIndexAnalysisTask.java

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -202,21 +202,22 @@ public void inform(final Event e) {
202202
SCANNER_OSSINDEX_API_TOKEN.getGroupName(),
203203
SCANNER_OSSINDEX_API_TOKEN.getPropertyName()
204204
);
205-
if (apiUsernameProperty == null
206-
|| apiUsernameProperty.getPropertyValue() == null
207-
|| apiTokenProperty == null
208-
|| apiTokenProperty.getPropertyValue() == null) {
209-
LOGGER.warn("An API username or token has not been specified for use with OSS Index; Skipping");
205+
if (apiTokenProperty == null || apiTokenProperty.getPropertyValue() == null) {
206+
LOGGER.warn("An API token has not been specified for use with OSS Index; Skipping");
210207
return;
211-
} else {
212-
try {
213-
apiUsername = apiUsernameProperty.getPropertyValue();
214-
apiToken = DebugDataEncryption.decryptAsString(apiTokenProperty.getPropertyValue());
215-
} catch (Exception ex) {
216-
// OSS Index will stop supporting unauthenticated requests
217-
LOGGER.error("An error occurred decrypting the OSS Index API Token; Skipping", ex);
208+
}
209+
try {
210+
apiToken = DebugDataEncryption.decryptAsString(apiTokenProperty.getPropertyValue());
211+
} catch (Exception ex) {
212+
LOGGER.error("An error occurred decrypting the OSS Index API Token; Skipping", ex);
213+
return;
214+
}
215+
if (!isBearerToken(apiToken)) {
216+
if (apiUsernameProperty == null || apiUsernameProperty.getPropertyValue() == null) {
217+
LOGGER.warn("An API username has not been specified for use with OSS Index; Skipping");
218218
return;
219219
}
220+
apiUsername = apiUsernameProperty.getPropertyValue();
220221
}
221222
aliasSyncEnabled = super.isEnabled(ConfigPropertyConstants.SCANNER_OSSINDEX_ALIAS_SYNC_ENABLED);
222223
}
@@ -322,6 +323,10 @@ private static String minimizePurl(final PackageURL purl) {
322323
return purl.getCoordinates().replaceFirst("@v", "@");
323324
}
324325

326+
private static boolean isBearerToken(final String token) {
327+
return token != null && token.startsWith("sonatype_pat_");
328+
}
329+
325330
/**
326331
* Submits the payload to the Sonatype OSS Index service
327332
*/
@@ -331,7 +336,9 @@ private List<ComponentReport> submit(final JSONObject payload) throws Throwable
331336
request.addHeader(HttpHeaders.CONTENT_TYPE, "application/json");
332337
request.addHeader(HttpHeaders.USER_AGENT, ManagedHttpClientFactory.getUserAgent());
333338
request.setEntity(new StringEntity(payload.toString()));
334-
if (apiUsername != null && apiToken != null) {
339+
if (isBearerToken(apiToken)) {
340+
request.addHeader("Authorization", "Bearer " + apiToken);
341+
} else if (apiUsername != null && apiToken != null) {
335342
request.addHeader("Authorization", HttpUtil.basicAuthHeaderValue(apiUsername, apiToken));
336343
}
337344
try (final CloseableHttpResponse response = RETRY.executeCheckedSupplier(() -> HttpClientPool.getClient().execute(request))) {

src/test/java/org/dependencytrack/tasks/scanners/OssIndexAnalysisTaskTest.java

Lines changed: 48 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -232,19 +232,62 @@ void testAnalyzeWithoutApiToken() {
232232
}
233233

234234
@Test
235-
void testAnalyzeWithoutUser() {
236-
configApiToken(null, API_TOKEN);
235+
void testAnalyzeWithoutUser() throws Exception {
236+
configApiToken(null, DataEncryption.encryptAsString(API_TOKEN));
237237
stubPOSTRequest();
238238

239239
var project = configProject();
240240

241241
var component = getComponent(project);
242242
qm.persist(component);
243243

244-
assertThatNoException().isThrownBy(() -> analysisTask.inform(new OssIndexAnalysisEvent(
245-
List.of(component), VulnerabilityAnalysisLevel.BOM_UPLOAD_ANALYSIS)));
244+
assertThatNoException().isThrownBy(
245+
() -> analysisTask.inform(
246+
new OssIndexAnalysisEvent(
247+
List.of(component),
248+
VulnerabilityAnalysisLevel.BOM_UPLOAD_ANALYSIS)));
246249

247-
verify(0, getRequestedPost());
250+
verify(0, postRequestedFor(urlPathEqualTo("/api/v3/component-report")));
251+
}
252+
253+
@Test
254+
void testAnalyzeWithBearerToken() throws Exception {
255+
final String bearerToken = "sonatype_pat_testtoken123";
256+
configApiToken(null, DataEncryption.encryptAsString(bearerToken));
257+
stubPOSTRequest();
258+
259+
var project = configProject();
260+
var component = getComponent(project);
261+
qm.persist(component);
262+
263+
assertThatNoException().isThrownBy(
264+
() -> analysisTask.inform(
265+
new OssIndexAnalysisEvent(
266+
List.of(component),
267+
VulnerabilityAnalysisLevel.BOM_UPLOAD_ANALYSIS)));
268+
269+
verify(postRequestedFor(urlPathEqualTo("/api/v3/component-report"))
270+
.withHeader("Authorization", equalTo("Bearer " + bearerToken)));
271+
}
272+
273+
@Test
274+
void testAnalyzeWithBearerTokenAndUsername() throws Exception {
275+
final String bearerToken = "sonatype_pat_testtoken123";
276+
configApiToken(API_USER, DataEncryption.encryptAsString(bearerToken));
277+
stubPOSTRequest();
278+
279+
var project = configProject();
280+
var component = getComponent(project);
281+
qm.persist(component);
282+
283+
assertThatNoException().isThrownBy(
284+
() -> analysisTask.inform(
285+
new OssIndexAnalysisEvent(
286+
List.of(component),
287+
VulnerabilityAnalysisLevel.BOM_UPLOAD_ANALYSIS)));
288+
289+
verify(postRequestedFor(urlPathEqualTo("/api/v3/component-report"))
290+
.withHeader("Authorization", equalTo("Bearer " + bearerToken)));
248291
}
249292

250293
private @NotNull Project configProject() {

0 commit comments

Comments
 (0)